openDB (db.go) built the SQLite connection string as file: + path + ? + parameters, unescaped. A ? or # in the path ended the file name and a % started an escape, so scan could silently create and fill a database under a shortened name. The path now goes into a net/urlfile: URL, which escapes it. The read-write connection for scan and the read-only one for report and trees both come from that one call.
What the diff does not show:
SQLite reads what follows file:// up to the next / as a host name. So an absolute path is written after an empty host (file:///abs) and a relative path with none (file:rel): OmitHost: !filepath.IsAbs(path). Leaving out the host for every path breaks a path starting with //; writing one for every path breaks relative paths. The test has a case for each.
Judgement call: the path is not cleaned or made absolute. Doing either would resolve .. without following symlinks, so the database could end up a different file from the lock file and from the existence check, which both use the path as given.
The test's file name holds %25 rather than a bare %. %25 is a valid escape, so under the old code the scan quietly writes a file named a instead of failing on a bad escape, which is the failure the issue describes.
README §Database now says the path names the file exactly and a relative path is relative to the working directory.
Model: opus-5-5
Fixes https://git.eeqj.de/sneak/sfdupes/issues/55.
`openDB` (`db.go`) built the SQLite connection string as `file:` + path + `?` + parameters, unescaped. A `?` or `#` in the path ended the file name and a `%` started an escape, so `scan` could silently create and fill a database under a shortened name. The path now goes into a `net/url` `file:` URL, which escapes it. The read-write connection for `scan` and the read-only one for `report` and `trees` both come from that one call.
What the diff does not show:
- SQLite reads what follows `file://` up to the next `/` as a host name. So an absolute path is written after an empty host (`file:///abs`) and a relative path with none (`file:rel`): `OmitHost: !filepath.IsAbs(path)`. Leaving out the host for every path breaks a path starting with `//`; writing one for every path breaks relative paths. The test has a case for each.
- Judgement call: the path is not cleaned or made absolute. Doing either would resolve `..` without following symlinks, so the database could end up a different file from the lock file and from the existence check, which both use the path as given.
- The test's file name holds `%25` rather than a bare `%`. `%25` is a valid escape, so under the old code the scan quietly writes a file named `a` instead of failing on a bad escape, which is the failure the issue describes.
README §Database now says the path names the file exactly and a relative path is relative to the working directory.
Model: opus-5-5
openDB put the path into the connection string unescaped, so a ? or #
in it ended the file name and a % started an escape: scan could
silently fill a database under a shortened name. The path now goes
through net/url as a file: URI. An absolute path gets an empty host and
a relative path none, because SQLite reads what follows file:// up to
the next slash as a host name. The path is not cleaned, so it stays
exactly what the operator gave.
A test runs scan, report and trees against such a file name given as an
absolute path, as one starting with //, and as a relative path, and
checks that only that file and its lock file exist afterwards.
Model: opus-5-5
Blocking a user prevents them from interacting with repositories, such as opening or commenting on pull requests or issues. Learn more about blocking a user.
Fixes #55.
openDB(db.go) built the SQLite connection string asfile:+ path +?+ parameters, unescaped. A?or#in the path ended the file name and a%started an escape, soscancould silently create and fill a database under a shortened name. The path now goes into anet/urlfile:URL, which escapes it. The read-write connection forscanand the read-only one forreportandtreesboth come from that one call.What the diff does not show:
file://up to the next/as a host name. So an absolute path is written after an empty host (file:///abs) and a relative path with none (file:rel):OmitHost: !filepath.IsAbs(path). Leaving out the host for every path breaks a path starting with//; writing one for every path breaks relative paths. The test has a case for each...without following symlinks, so the database could end up a different file from the lock file and from the existence check, which both use the path as given.%25rather than a bare%.%25is a valid escape, so under the old code the scan quietly writes a file namedainstead of failing on a bad escape, which is the failure the issue describes.README §Database now says the path names the file exactly and a relative path is relative to the working directory.
Model: opus-5-5
Review passed.
Model: opus-5-5