I have discovered that opening a database via a symlink works only if the 
symlink is in the current directory. Otherwise, this happens:

; mkdir x y
; sqlite3 x/foo.sqlite 'create table foo(x);'
; sqlite3 x/foo.sqlite 'select count(*) from foo;'
0
; ln -s ../x/foo.sqlite y
; cmp x/foo.sqlite y/foo.sqlite
; sqlite3 y/foo.sqlite 'select count(*) from foo;'
Error: unable to open database "y/foo.sqlite": unable to open database file

The problem seems to have been introduced with this revision:

uuid: ? ? ? ? c7c8105099c0412ac6c605f98987092c10bde57c 2015-10-31 17:58:33 UTC
parent: ? ? ? 9f19420b0a79dff65fc3a9d548f4b3fc4955f9f9 2015-10-30 20:54:25 UTC
merged-into: ?6d5ce3ede4c7038c19a77268a5a7b9d5650933c2 2015-11-02 15:08:56 UTC
tags: ? ? ? ? follow-symlinks
comment: ? ? ?On unix, if a file is opened via a symlink, create, read and
? ? ? ? ? ? ? write journal and wal files based on the name of the actual db
? ? ? ? ? ? ? file, not the symlink. (user: dan)

Reading the source code for?unixFullPathname in src/os_unix.c, I see that the 
filename is created by appending a slash, then the contents of the symlink, to 
the current working directory. This is wrong, unless the symlink is in the 
current working directory.

I think the proper algorithm should go like this, if the given filename is a 
symlink:

Read the contents of the symlink. If it begins with a slash, replace the 
original filename by this.

Otherwise, split up the given filename as ?dirname/filename? where filename 
containsno slashes, but dirname may. (Do nothing if the given filename contains 
no slashes to begin with).

Append a slash and the contents of the symlink to ?dirname?. This is the new 
filename. (If the given filename contained no slash, just use the contents of 
the symlink.)

Finally, don?t forget that the symlink may point to a symlink! If so, repeat 
the whole procedure. Repeat until the target is not an existing symlink, or 
some counter signals a likely symlink loop. (Aim to use the same limit as the 
built-in symlink resolution algorithm.)

Only after all this is done, and only if absolute filenames are required, 
should the resulting filename be appended to the current working directory.

One final parenthetical remark:
I assume the code creates an absolute filename because the program might change 
working directory, and the sqlite code must be able to create new temporary 
files in the directory of the database file, is that right? But this can 
backfire if getcwd fails:

; mkdir -p /tmp/foo/bar
; cd /tmp/foo/bar
; chmod 000 /tmp/foo
; sqlite3 foo.sqlite 'create table foo (x);'
Error: unable to open database "foo.sqlite": unable to open database file

This error will surely be mystifying to whoever encounters it. At least, it 
would be good if the inability to run getcwd makes it into the error message 
somehow.

? Harald

Reply via email to