Robert Simpson wrote:
What I say below is in no means trying to be rude or show you (or
anyone) up. I have no idea what your experiences are with Windows or
Unix or Unix-Like operating systems. I'm probably stating things that
almost all of us already know. :)
So? If you open the file, that's 1 handle open. Someone unlinks it,
but a handle is still open. sqlite3_open() then opens the file,
that's 2 handles. You then close your handle and there's still 1
handle open until sqlite is done with it. I'm not a *nix programmer,
so maybe I am missing something obvious.
In Unix you can delete an open file. The file is simply removed from
the directory. Properly, this is called "unlinking". The actual
syscall is called "unlink". When a file has 0 hard-links, and no
process has it open, it is removed from the file system and the space
reclaimed. Normal files have only one "hard-link". The 'hard-link'
count is stored in the file's inode in a traditional unix file system.
(I know about UFS and EXT2/EXT3. I have no idea what JFS, XFS,
ReiserFS, et al do.)
In Windows you can not delete an open file, even if your process has the
file open for writing. The text at the bottom was lifted directly from
the February 2003 Win32 platform SDK on the "DeleteFile" API call [1]
about 15 seconds ago. Note that the rules I'm discussing are for NT
kernel based versions of Windows.
#2.. Would that work if you opened the file exclusively? If you
don't open it exclusively, theoretically someone else could open it too.
On Windows, sqlite3_open() calls the CreateFile() API with the
OPEN_ALWAYS flag, which means if the file doesn't exist, then create
it -- in either case, always open the file. To atomically create a
file and make sqlite3 open it (at least in Windows) you would call
CreateFile() with the CREATE_NEW flag, which will atomically fail if
the file already exists. If it creates a new file however, you can
then pass the filename to sqlite3_open() and then subsequently close
your handle.
I know :) I'm simply saying that I wish that sqlite3_open() took some
flags and "did the right thing" based on the underling OS. Those flags
would be specific to sqlite and translated into the native OS flags deep
inside to "os_***.c" wrappers.
#define SQLITE3_OPEN_DEFAULT 0
#define SQLITE3_OPEN_EXISTING 1
#define SQLITE3_OPEN_TRUNCATE 2
...etc...
So my question is simply, "Why was sqlite3 designed to behave the way it
does?" (That is, the caller has no control over the underlying "open"
operation.
Another option would be to create a version of "sqlite3_open" that takes
an existing OS handle and uses the handle as-is (I suppose that you'd
still have to pass in a filename so that the journal, vacuum, (and
other?), files could be created).
Now, I've not had a need for any of this. I did notice this a long time
ago though. If I really needed this, I'd code it myself. I've already
hacked away on the sqlite code base to make it do some things that I
want it to do.
[1]
If an application attempts to delete a file that does not exist, the
*DeleteFile* function fails. If the file is a read-only file, the
function fails with ERROR_ACCESS_DENIED. To delete a read-only file, you
must first remove the read-only attribute.
To delete or rename a file, you must have either delete permission on
the file or delete child permission in the parent directory. If you set
up a directory with all access except delete and delete child and the
ACLs of new files are inherited, then you should be able to create a
file without being able to delete it. However, you can then create a
file get all the access you request on the handle returned to you at the
time you create the file. If you requested delete permission at the time
you created the file, you could delete or rename the file with that
handle but not with any other. For more information, see File Security
and Access Rights <file_security_and_access_rights.htm>.
The *DeleteFile* function fails if an application attempts to delete a
file that is open for normal I/O or as a memory-mapped file.
*Windows Me/98/95: *The *DeleteFile* function deletes a file even if it
is open for normal I/O or as a memory-mapped file. To prevent loss of
data, close files before attempting to delete them.
To recursively delete the files in a directory, use the
*SHFileOperation* function.
To close an open file, use the *CloseHandle* function.
The *DeleteFile* function marks a file for deletion on close. Therefore,
the file deletion does not occur until the last handle to the file is
closed. Subsequent calls to *CreateFile* <createfile.htm> to open the
file fail with ERROR_ACCESS_DENIED.
*Windows Me/98/95: **DeleteFileW* is supported by the Microsoft Layer
for Unicode. To use this, you must add certain files to your
application, as outlined in Microsoft Layer for Unicode on
Windows 95/98/Me Systems.