See parent: transport
Plugin files are named pwsafe-<scheme>.so (e.g. pwsafe-webdav.so, pwsafe-file.so, pwsafe-s3.so). When a scheme is needed, the loader constructs the filename directly — no directory scan required.
Search path (in order):
1. Directory containing the application binary (via /proc/self/exe on Linux)
2. Current working directory — #ifdef DEVELOPMENT builds only (security: avoid loading arbitrary plugins from cwd in production)
Every plugin embeds a static string. After finding the file by name, the loader verifies it before dlopen as a sanity check against renamed files:
static const char pws_transport_info[] =
"PWS_TRANSPORT_INFO:1:http,https:WebDAV store via libcurl";
// ^ ^-scheme(s)-^ ^----description----^
// ABI version
Format: PWS_TRANSPORT_INFO:<abi>:<scheme>[,scheme,...]:<description>
Examples:
PWS_TRANSPORT_INFO:1:file:Local file transport (testing)
PWS_TRANSPORT_INFO:1:http,https:WebDAV transport via libcurl
PWS_TRANSPORT_INFO:1:s3:Amazon S3 transport
Verification is a raw-bytes scan (fopen + memmem) — no dlopen needed. If the identity string is absent or the scheme doesn't match the filename, the file is rejected with a clear error. Readable externally with strings pwsafe-webdav.so | grep PWS_TRANSPORT_INFO.
1. User enters a URL — scheme extracted (e.g. webdav)
2. Construct filename: pwsafe-webdav.so
3. Search for it in path order (app dir, then cwd if DEVELOPMENT)
4. If not found → popup error, offer retry; stop
5. Pre-scan raw bytes: verify PWS_TRANSPORT_INFO: string matches scheme and ABI
6. If mismatch → error ("file may have been renamed"); stop
7. dlopen the file
8. Call pws_plugin_init(register_fn)
9. If init fails → dlclose, error; stop
10. Plugin is live — use it for this database session
A plugin is loaded when its scheme is first needed and unloaded when the database using it is closed (or when the user switches to a plain file path). Only one plugin is live at a time. If the same scheme is needed again in the same session, it is reloaded.
First match wins: the assumption is at most one pwsafe-<scheme>.so per scheme on the search path. If duplicates exist, the one in the app binary directory takes precedence.
• No prefix, or plain OS path → no plugin → existing local file code, unchanged
• file:///path → pwsafe-file.so (reference/test plugin)
• webdav:https://host/path → pwsafe-webdav.so (strips own prefix, passes https://... to libcurl)
• s3://bucket/key → pwsafe-s3.so