Skip to content

Commit 38119b5

Browse files
committed
fix opening db through symlink or relative to root directory
1 parent a90ed8b commit 38119b5

3 files changed

Lines changed: 34 additions & 3 deletions

File tree

.github/workflows/tests.yml

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,8 @@ jobs:
2525
/usr/local/bin/pip3 install pytest pytest-xdist
2626
- name: build
2727
run: |
28-
CXXFLAGS=-I$(brew --prefix)/include LDFLAGS=-L$(brew --prefix)/lib \
28+
CXXFLAGS="-I$(brew --prefix)/include -I$(brew --prefix)/opt/sqlite/include" \
29+
LDFLAGS="-L$(brew --prefix)/lib -L$(brew --prefix)/opt/sqlite/lib" \
2930
cmake -DCMAKE_BUILD_TYPE=${{ matrix.BUILD_TYPE }} \
3031
-DCMAKE_PREFIX_PATH=$(brew --prefix)/opt/sqlite \
3132
-B build .

src/SQLiteNestedVFS.h

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@
2323
#include <libgen.h>
2424
#include <memory>
2525
#include <string>
26+
#include <unistd.h>
2627
#include <vector>
2728

2829
#include <iostream>
@@ -1116,8 +1117,17 @@ class VFS : public SQLiteVFS::Wrapper {
11161117
// append a suffix as the inner db's filename (which won't actually exist on the host
11171118
// filesystem, but xOpen() will recognize).
11181119
int FullPathname(const char *zName, int nPathOut, char *zPathOut) override {
1119-
int rc = SQLiteVFS::Wrapper::FullPathname(zName, nPathOut, zPathOut);
1120-
if (rc != SQLITE_OK) {
1120+
std::string zName2(zName);
1121+
if (!zName2.empty() && zName2[0] != '/') {
1122+
if (getcwd(zPathOut, nPathOut) && !strcmp(zPathOut, "/")) {
1123+
// evading bug in sqlite3 os_unix.c unixFullPathname, when given a relative path
1124+
// and the cwd is / (this tends to happen in docker)
1125+
zName2 = "/" + zName2;
1126+
}
1127+
}
1128+
int rc = SQLiteVFS::Wrapper::FullPathname(zName2.c_str(), nPathOut, zPathOut);
1129+
if (rc != SQLITE_OK && rc != SQLITE_OK_SYMLINK) {
1130+
_DBG << "FullPathNameE " << rc << " " << sqlite3_errstr(rc) << _EOL;
11211131
return rc;
11221132
}
11231133
std::string outer_db_filename(zPathOut);

test/test.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -130,6 +130,26 @@ def test_roundtrip_zstd(tmpdir, chinook_file):
130130
actual = [stmt.strip() for stmt in rslt.stdout.split(";\n")]
131131
assert actual == expected
132132

133+
# test reopen through symlink
134+
linkpath = os.path.join(tmpdir, "symlink")
135+
os.symlink(dbfn, linkpath)
136+
assert os.path.realpath(linkpath) == os.path.realpath(dbfn)
137+
linkcon = sqlite3.connect(f"file:{linkpath}?vfs=zstd", uri=True)
138+
linkcon.execute("select 1")
139+
140+
141+
@pytest.mark.skipif(os.geteuid() != 0, reason="must run in docker")
142+
def test_db_in_root():
143+
# regression test, create db with relative path to root directory
144+
# (this tends to happen in docker)
145+
con = sqlite3.connect(f":memory:")
146+
con.enable_load_extension(True)
147+
con.load_extension(os.path.join(BUILD, "zstd_vfs"))
148+
os.chdir("/")
149+
con = sqlite3.connect(f"file:test_in_root.db?vfs=zstd", uri=True)
150+
con.executescript("CREATE TABLE hello(x INTEGER)")
151+
con.commit()
152+
133153

134154
def test_vacuum(tmpdir, chinook_file):
135155
# open the zstd database

0 commit comments

Comments
 (0)