Index: /trunk/include/iprt/crypto/store.h
===================================================================
--- /trunk/include/iprt/crypto/store.h	(revision 57612)
+++ /trunk/include/iprt/crypto/store.h	(revision 57613)
@@ -29,4 +29,5 @@
 #include <iprt/crypto/x509.h>
 #include <iprt/crypto/taf.h>
+#include <iprt/sha.h>
 
 
@@ -56,4 +57,36 @@
 /** Pointer to a certificate store search. */
 typedef RTCRSTORECERTSEARCH *PRTCRSTORECERTSEARCH;
+
+
+/**
+ * Info about a wanted certificate.
+ *
+ * All the search criteria are optional, but for a safe and efficient search
+ * it's recommended to specify all possible ones.  If none are given, the search
+ * function will fail.
+ *
+ * For use with RTCrStoreCertAddFromFishingExpedition and others.
+ */
+typedef struct RTCRCERTWANTED
+{
+    /** The certificate subject name, optional.
+     * The format is: "C=US, ST=California, L=Redwood Shores, O=Oracle Corporation" */
+    const char *pszSubject;
+    /** The size of the DER (ASN.1) encoded certificate, optional (0). */
+    uint16_t    cbEncoded;
+    /** Set if abSha1 contains a valid SHA-1 fingerprint. */
+    bool        fSha1Fingerprint;
+    /** Set if abSha512 contains a valid SHA-512 fingerprint. */
+    bool        fSha512Fingerprint;
+    /** The SHA-1 fingerprint (of the encoded data).   */
+    uint8_t     abSha1[RTSHA1_HASH_SIZE];
+    /** The SHA-512 fingerprint (of the encoded data).   */
+    uint8_t     abSha512[RTSHA512_HASH_SIZE];
+    /** User pointer for directly associating other data with the entry.
+     * Subclassing the structure isn't possible because it's passed as an array. */
+    void const *pvUser;
+} RTCRCERTWANTED;
+/** Pointer to a const certificat wanted structure. */
+typedef RTCRCERTWANTED const *PCRTCRCERTWANTED;
 
 
@@ -162,4 +195,8 @@
                                     PCRTSTRTUPLE paSuffixes, size_t cSuffixes, PRTERRINFO pErrInfo);
 
+RTDECL(int) RTCrStoreCertAddWantedFromDir(RTCRSTORE hStore, uint32_t fFlags,
+                                          const char *pszDir, PCRTSTRTUPLE paSuffixes, size_t cSuffixes,
+                                          PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo);
+
 /**
  * Adds certificates from the specified file.
@@ -183,4 +220,7 @@
 RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo);
 
+RTDECL(int) RTCrStoreCertAddWantedFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename,
+                                           PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo);
+
 /**
  * Adds certificates from the specified java key store file.
@@ -229,4 +269,14 @@
  */
 RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc);
+
+RTDECL(int) RTCrStoreCertAddWantedFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hSrcStore,
+                                            PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound);
+
+RTDECL(int) RTCrStoreCertCheckWanted(RTCRSTORE hStore, PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound);
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromFishingExpedition(RTCRSTORE hStore, uint32_t fFlags,
+                                                        PCRTCRCERTWANTED paWanted, size_t cWanted,
+                                                        bool *pafFound, PRTERRINFO pErrInfo);
 
 /**
@@ -240,4 +290,12 @@
  */
 RTDECL(int) RTCrStoreCertExportAsPem(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename);
+
+/**
+ * Counts the number of certificates in the store.
+ *
+ * @returns Certificate count on success, UINT32_MAX on failure.
+ * @param   hStore              The store which certificates should be counted.
+ */
+RTDECL(uint32_t) RTCrStoreCertCount(RTCRSTORE hStore);
 
 RTDECL(int) RTCrStoreCertFindAll(RTCRSTORE hStore, PRTCRSTORECERTSEARCH pSearch);
Index: /trunk/include/iprt/dir.h
===================================================================
--- /trunk/include/iprt/dir.h	(revision 57612)
+++ /trunk/include/iprt/dir.h	(revision 57613)
@@ -236,5 +236,5 @@
  *
  * This is the RTFS_TYPE_MASK stuff shifted down 12 bits and
- * identical to the BSD/LINUX ABI.
+ * identical to the BSD/LINUX ABI.  See RTFS_TYPE_DIRENTRYTYPE_SHIFT.
  */
 typedef enum RTDIRENTRYTYPE
Index: /trunk/include/iprt/err.h
===================================================================
--- /trunk/include/iprt/err.h	(revision 57612)
+++ /trunk/include/iprt/err.h	(revision 57613)
@@ -2478,5 +2478,5 @@
 /** @name RTCrDigest status codes.
  * @{ */
-/** OpenSSL failed to initialize the digest algorithm contextn. */
+/** OpenSSL failed to initialize the digest algorithm context. */
 #define VERR_CR_DIGEST_OSSL_DIGEST_INIT_ERROR       (-24200)
 /** OpenSSL failed to clone the digest algorithm context. */
@@ -2484,4 +2484,16 @@
 /** @} */
 
+/** @name RTPath  status codes.
+ * @{ */
+/** Unknown glob variable.  */
+#define VERR_PATH_MATCH_UNKNOWN_VARIABLE            (-24400)
+/** The specified glob variable must be first in the pattern. */
+#define VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST      (-24401)
+/** Hit unimplemented glob pattern matching feature.  */
+#define VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED     (-24402)
+/** Unknown character class in glob pattern.   */
+#define VERR_PATH_GLOB_UNKNOWN_CHAR_CLASS           (-24403)
+/** @} */
+
 /* SED-END */
 
Index: /trunk/include/iprt/file.h
===================================================================
--- /trunk/include/iprt/file.h	(revision 57612)
+++ /trunk/include/iprt/file.h	(revision 57613)
@@ -778,4 +778,18 @@
 RTDECL(int) RTFileCreateTempSecure(char *pszTemplate);
 
+/**
+ * Opens a new file with a unique name in the temp directory.
+ *
+ * @returns iprt status code.
+ * @param   pszTemplate     The file name template on input. The actual file
+ *                          name on success. Empty string on failure.
+ * @param   fMode           The mode to create the file with.  Use 0600 unless
+ *                          you have reason not to.
+ *
+ * @remarks If actual control over the filename or location is required, we'll
+ *          create an extended edition of this API.
+ */
+RTDECL(int) RTFileOpenTemp(PRTFILE pFile, char *pszFilename, size_t cbFilename, uint64_t fOpen);
+
 
 /** @page   pg_rt_filelock      RT File locking API description
Index: /trunk/include/iprt/fs.h
===================================================================
--- /trunk/include/iprt/fs.h	(revision 57612)
+++ /trunk/include/iprt/fs.h	(revision 57613)
@@ -117,4 +117,6 @@
 /** Type mask (S_IFMT). */
 #define RTFS_TYPE_MASK              0170000U
+/** The shift count to convert between RTFS_TYPE_MASK and DIRENTRYTYPE. */
+#define RTFS_TYPE_DIRENTRYTYPE_SHIFT    12
 
 /** Unix attribute mask. */
@@ -593,4 +595,15 @@
 RTR3DECL(int) RTFsQueryProperties(const char *pszFsPath, PRTFSPROPERTIES pProperties);
 
+/**
+ * Checks if the given volume is case sensitive or not.
+ *
+ * This may be misleading in some cases as we lack the necessary APIs to query
+ * the information on some system (or choose not to use them) and are instead
+ * returning the general position on case sensitive file name of the system.
+ *
+ * @returns @c true if case sensitive, @c false if not.
+ * @param   pszFsPath       Path within the mounted file system.
+ */
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath);
 
 /**
Index: /trunk/include/iprt/http.h
===================================================================
--- /trunk/include/iprt/http.h	(revision 57612)
+++ /trunk/include/iprt/http.h	(revision 57613)
@@ -1,5 +1,5 @@
 /* $Id$ */
 /** @file
- * IPRT - Simple HTTP Communication API.
+ * IPRT - Simple HTTP/HTTPS Client API.
  */
 
@@ -32,5 +32,5 @@
 RT_C_DECLS_BEGIN
 
-/** @defgroup grp_rt_http   RTHttp - Simple HTTP API
+/** @defgroup grp_rt_http   RTHttp - Simple HTTP/HTTPS Client API
  * @ingroup grp_rt
  * @{
@@ -38,14 +38,14 @@
 
 /** @todo the following three definitions may move the iprt/types.h later. */
-/** RTHTTP interface handle. */
+/** HTTP/HTTPS client handle. */
 typedef R3PTRTYPE(struct RTHTTPINTERNAL *)      RTHTTP;
-/** Pointer to a RTHTTP interface handle. */
-typedef RTHTTP                                  *PRTHTTP;
-/** Nil RTHTTP interface handle. */
+/** Pointer to a HTTP/HTTPS client handle. */
+typedef RTHTTP                                 *PRTHTTP;
+/** Nil HTTP/HTTPS client handle. */
 #define NIL_RTHTTP                              ((RTHTTP)0)
 
 
 /**
- * Creates a HTTP interface handle.
+ * Creates a HTTP client instance.
  *
  * @returns iprt status code.
@@ -56,5 +56,5 @@
 
 /**
- * Destroys a HTTP interface handle.
+ * Destroys a HTTP client instance.
  *
  * @param   hHttp       Handle to the HTTP interface.
@@ -80,6 +80,6 @@
  * @returns iprt status code.
  *
- * @param   hHttp           HTTP interface handle.
- * @param   pcszUrl         URL.
+ * @param   hHttp           The HTTP client instance.
+ * @param   pszUrl          URL.
  * @param   ppszNotUtf8     Where to return the poitner to the HTTP response.
  *                          The string is of course zero terminated.  Use
@@ -99,5 +99,5 @@
  *          containing embedded zero's, use RTHttpGetBinary instead.
  */
-RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pcszUrl, char **ppszNotUtf8);
+RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8);
 
 /**
@@ -113,11 +113,11 @@
  * @returns iprt status code.
  *
- * @param   hHttp           HTTP interface handle.
- * @param   pcszUrl         The URL.
+ * @param   hHttp           The HTTP client instance.
+ * @param   pszUrl          The URL.
  * @param   ppvResponse     Where to store the HTTP response data.  Use
  *                          RTHttpFreeResponse to free.
  * @param   pcb             Size of the returned buffer.
  */
-RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pcszUrl, void **ppvResponse, size_t *pcb);
+RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb);
 
 /**
@@ -133,5 +133,5 @@
  * @returns iprt status code.
  *
- * @param   hHttp           HTTP interface handle.
+ * @param   hHttp           The HTTP client instance.
  * @param   pszUrl          The URL.
  * @param   pszDstFile      The destination file name.
@@ -146,5 +146,5 @@
  * @returns iprt status code.
  *
- * @param   hHttp           HTTP interface handle.
+ * @param   hHttp           The HTTP client instance.
  */
 RTR3DECL(int) RTHttpAbort(RTHTTP hHttp);
@@ -154,5 +154,5 @@
  *
  * @returns iprt status code.
- * @param   hHttp           HTTP interface handle.
+ * @param   hHttp           The HTTP client instance.
  */
 RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp);
@@ -163,12 +163,12 @@
  * @returns iprt status code.
  *
- * @param   hHttp           HTTP interface handle.
- * @param   pcszProxy       URL of the proxy.
+ * @param   hHttp           The HTTP client instance.
+ * @param   pszProxy        URL of the proxy.
  * @param   uPort           port number of the proxy, use 0 for not specifying a port.
- * @param   pcszUser        Username, pass NULL for no authentication.
- * @param   pcszPwd         Password, pass NULL for no authentication.
- */
-RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pcszProxyUrl, uint32_t uPort,
-                             const char *pcszProxyUser, const char *pcszProxyPwd);
+ * @param   pszProxyUser    Username, pass NULL for no authentication.
+ * @param   pszProxyPwd     Password, pass NULL for no authentication.
+ */
+RTR3DECL(int) RTHttpSetProxy(RTHTTP hHttp, const char *pszProxyUrl, uint32_t uPort,
+                             const char *pszProxyUser, const char *pszProxyPwd);
 
 /**
@@ -177,20 +177,64 @@
  * @returns iprt status code.
  *
- * @param   hHttp           HTTP interface handle.
+ * @param   hHttp           The HTTP client instance.
  * @param   cHeaders        Number of custom headers.
- * @param   pcszHeaders     Array of headers in form "foo: bar".
+ * @param   papszHeaders    Array of headers in form "foo: bar".
  */
 RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders);
 
 /**
+ * Tells the HTTP client instance to gather system CA certificates into a
+ * temporary file and use it for HTTPS connections.
+ *
+ * This will be called automatically if a 'https' URL is presented and
+ * RTHttpSetCaFile hasn't been called yet.
+ *
+ * @returns IPRT status code.
+ * @param   hHttp           The HTTP client instance.
+ * @param   pErrInfo        Where to store additional error/warning information.
+ *                          Optional.
+ */
+RTR3DECL(int) RTHttpUseTemporaryCaFile(RTHTTP hHttp, PRTERRINFO pErrInfo);
+
+/**
  * Set a custom certification authority file, containing root certificates.
  *
  * @returns iprt status code.
  *
- * @param   hHttp           HTTP interface handle.
- * @param   pcszCAFile      File name containing root certificates.
- */
-RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile);
-
+ * @param   hHttp           The HTTP client instance.
+ * @param   pszCAFile       File name containing root certificates.
+ *
+ * @remarks For portable HTTPS support, use RTHttpGatherCaCertsInFile and pass
+ */
+RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pszCAFile);
+
+/**
+ * Gathers certificates into a cryptographic (certificate) store
+ *
+ * This is a just a combination of RTHttpGatherCaCertsInStore and
+ * RTCrStoreCertExportAsPem.
+ *
+ * @returns IPRT status code.
+ * @param   hStore          The certificate store to gather the certificates
+ *                          in.
+ * @param   fFlags          RTHTTPGATHERCACERT_F_XXX.
+ * @param   pErrInfo        Where to store additional error/warning information.
+ *                          Optional.
+ */
+RTR3DECL(int) RTHttpGatherCaCertsInStore(RTCRSTORE hStore, uint32_t fFlags, PRTERRINFO pErrInfo);
+
+/**
+ * Gathers certificates into a file that can be used with RTHttpSetCAFile.
+ *
+ * This is a just a combination of RTHttpGatherCaCertsInStore and
+ * RTCrStoreCertExportAsPem.
+ *
+ * @returns IPRT status code.
+ * @param   pszCaFile       The output file.
+ * @param   fFlags          RTHTTPGATHERCACERT_F_XXX.
+ * @param   pErrInfo        Where to store additional error/warning information.
+ *                          Optional.
+ */
+RTR3DECL(int) RTHttpGatherCaCertsInFile(const char *pszCaFile, uint32_t fFlags, PRTERRINFO pErrInfo);
 
 /** @} */
Index: /trunk/include/iprt/mangling.h
===================================================================
--- /trunk/include/iprt/mangling.h	(revision 57612)
+++ /trunk/include/iprt/mangling.h	(revision 57613)
@@ -603,4 +603,5 @@
 # define RTFileOpenF                                    RT_MANGLER(RTFileOpenF)
 # define RTFileOpenV                                    RT_MANGLER(RTFileOpenV)
+# define RTFileOpenTemp                                 RT_MANGLER(RTFileOpenTemp)
 # define RTFileQueryFsSizes                             RT_MANGLER(RTFileQueryFsSizes)
 # define RTFileQueryInfo                                RT_MANGLER(RTFileQueryInfo)
@@ -628,4 +629,5 @@
 # define RTFileWriteAt                                  RT_MANGLER(RTFileWriteAt)
 # define RTFilesystemVfsFromFile                        RT_MANGLER(RTFilesystemVfsFromFile)
+# define RTFsIsCaseSensitive                            RT_MANGLER(RTFsIsCaseSensitive)
 # define RTFsQueryProperties                            RT_MANGLER(RTFsQueryProperties)
 # define RTFsQuerySerial                                RT_MANGLER(RTFsQuerySerial)
@@ -1061,4 +1063,6 @@
 # define RTPathGetCurrentOnDrive                        RT_MANGLER(RTPathGetCurrentOnDrive)
 # define RTPathGetMode                                  RT_MANGLER(RTPathGetMode)
+# define RTPathGlob                                     RT_MANGLER(RTPathGlob)
+# define RTPathGlobFree                                 RT_MANGLER(RTPathGlobFree)
 # define RTPathHasSuffix                                RT_MANGLER(RTPathHasSuffix)
 # define RTPathHasPath                                  RT_MANGLER(RTPathHasPath)
@@ -2892,4 +2896,5 @@
 # define RTCrStoreCertAddEncoded                        RT_MANGLER(RTCrStoreCertAddEncoded)
 # define RTCrStoreCertByIssuerAndSerialNo               RT_MANGLER(RTCrStoreCertByIssuerAndSerialNo)
+# define RTCrStoreCertCount                             RT_MANGLER(RTCrStoreCertCount)
 # define RTCrStoreCertFindAll                           RT_MANGLER(RTCrStoreCertFindAll)
 # define RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280 RT_MANGLER(RTCrStoreCertFindBySubjectOrAltSubjectByRfc5280)
@@ -2907,4 +2912,9 @@
 # define RTCrStoreCertAddFromJavaKeyStoreInMem          RT_MANGLER(RTCrStoreCertAddFromJavaKeyStoreInMem)
 # define RTCrStoreCertAddFromStore                      RT_MANGLER(RTCrStoreCertAddFromStore)
+# define RTCrStoreCertAddWantedFromDir                  RT_MANGLER(RTCrStoreCertAddWantedFromDir)
+# define RTCrStoreCertAddWantedFromFile                 RT_MANGLER(RTCrStoreCertAddWantedFromFile)
+# define RTCrStoreCertAddWantedFromStore                RT_MANGLER(RTCrStoreCertAddWantedFromStore)
+# define RTCrStoreCertAddWantedFromFishingExpedition    RT_MANGLER(RTCrStoreCertAddWantedFromFishingExpedition)
+# define RTCrStoreCertCheckWanted                       RT_MANGLER(RTCrStoreCertCheckWanted)
 # define RTCrStoreCertExportAsPem                       RT_MANGLER(RTCrStoreCertExportAsPem)
 # define RTErrInfoAdd                                   RT_MANGLER(RTErrInfoAdd)
Index: /trunk/include/iprt/path.h
===================================================================
--- /trunk/include/iprt/path.h	(revision 57612)
+++ /trunk/include/iprt/path.h	(revision 57613)
@@ -601,5 +601,5 @@
  * The first component is the root, volume or UNC specifier, if present.  Use
  * RTPATH_PROP_HAS_ROOT_SPEC() on RTPATHPARSED::fProps to determine its
- * precense.
+ * presence.
  *
  * Other than the root component, no component will include directory separators
@@ -1172,4 +1172,70 @@
 RTDECL(int) RTPathTemp(char *pszPath, size_t cchPath);
 
+
+/**
+ * RTPathGlobl result entry.
+ */
+typedef struct RTPATHGLOBENTRY
+{
+    /** List entry. */
+    struct RTPATHGLOBENTRY *pNext;
+    /** RTDIRENTRYTYPE value. */
+    uint8_t                 uType;
+    /** Unused explicit padding. */
+    uint8_t                 bUnused;
+    /** The length of the path. */
+    uint16_t                cchPath;
+    /** The path to the file (variable length). */
+    char                    szPath[1];
+} RTPATHGLOBENTRY;
+/** Pointer to a GLOB result entry. */
+typedef RTPATHGLOBENTRY *PRTPATHGLOBENTRY;
+/** Pointer to a const GLOB result entry. */
+typedef RTPATHGLOBENTRY const *PCRTPATHGLOBENTRY;
+/** Pointer to a GLOB result entry pointer. */
+typedef PCRTPATHGLOBENTRY *PPCRTPATHGLOBENTRY;
+
+/**
+ * Performs wildcard expansion on a path pattern.
+ *
+ * @returns IPRT status code.
+ *
+ * @param   pszPattern      The pattern to expand.
+ * @param   fFlags          RTPATHGLOB_F_XXX.
+ * @param   ppHead          Where to return the head of the result list.  This
+ *                          is always set to NULL on failure.
+ * @param   pcResults       Where to return the number of the result. Optional.
+ */
+RTDECL(int) RTPathGlob(const char *pszPattern, uint32_t fFlags, PPCRTPATHGLOBENTRY ppHead, uint32_t *pcResults);
+
+/** @name RTPATHGLOB_F_XXX - RTPathGlob flags
+ *  @{ */
+/** Case insensitive. */
+#define RTPATHGLOB_F_IGNORE_CASE        RT_BIT_32(0)
+/** Do not expand \${EnvOrSpecialVariable} in the pattern. */
+#define RTPATHGLOB_F_NO_VARIABLES       RT_BIT_32(1)
+/** Do not interpret a leading tilde as a home directory reference. */
+#define RTPATHGLOB_F_NO_TILDE           RT_BIT_32(2)
+/** Only return the first match. */
+#define RTPATHGLOB_F_FIRST_ONLY         RT_BIT_32(3)
+/** Only match directories (implied if pattern ends with slash). */
+#define RTPATHGLOB_F_ONLY_DIRS          RT_BIT_32(4)
+/** Do not match directories.  (Can't be used with RTPATHGLOB_F_ONLY_DIRS or
+ * patterns containing a trailing slash.) */
+#define RTPATHGLOB_F_NO_DIRS            RT_BIT_32(5)
+/** Disables the '**' wildcard pattern for matching zero or more subdirs. */
+#define RTPATHGLOB_F_NO_STARSTAR        RT_BIT_32(6)
+/** Mask of valid flags. */
+#define RTPATHGLOB_F_MASK               UINT32_C(0x0000007f)
+/** @} */
+
+/**
+ * Frees the results produced by RTPathGlob.
+ *
+ * @param   pHead           What RTPathGlob returned.  NULL ignored.
+ */
+RTDECL(void) RTPathGlobFree(PCRTPATHGLOBENTRY pHead);
+
+
 /**
  * Query information about a file system object.
Index: /trunk/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp
===================================================================
--- /trunk/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp	(revision 57612)
+++ /trunk/src/VBox/Frontends/VirtualBox/src/net/UINetworkReply.cpp	(revision 57613)
@@ -72,11 +72,18 @@
 
 private:
+    /** @name Helpers - HTTP stuff
+     * @{ */
+    int applyProxyRules();
+    int applyHttpsCertificates();
+    int applyRawHeaders();
+    int performMainRequest();
+    /** @} */
+
+    /* Helper: Main thread runner: */
+    void run();
+
     /** Info about wanted certificate. */
     typedef struct CERTINFO
     {
-        /** The certificate subject name. */
-        const char *pszSubject;
-        /** The size of the DER (ASN.1) encoded certificate. */
-        uint16_t    cbEncoded;
         /** Gives the s_aCerts index this certificate is an alternative edition of,
          * UINT8_MAX if no alternative.  This is a complication caused by VeriSign
@@ -87,8 +94,4 @@
         /** Set if mandatory. */
         bool        fMandatory;
-        /** The SHA-1 fingerprint (of the encoded data).   */
-        uint8_t     abSha1[RTSHA1_HASH_SIZE];
-        /** The SHA-512 fingerprint (of the encoded data).   */
-        uint8_t     abSha512[RTSHA512_HASH_SIZE];
         /** Filename in the zip file we download (PEM). */
         const char *pszZipFile;
@@ -97,16 +100,4 @@
     } CERTINFO;
 
-
-    /** @name Helpers - HTTP stuff
-     * @{ */
-    int applyProxyRules();
-    int applyHttpsCertificates();
-    int applyRawHeaders();
-    int performMainRequest();
-    /** @} */
-
-    /* Helper: Main thread runner: */
-    void run();
-
     /** @name Static helpers for HTTP and Certificates handling.
      * @{ */
@@ -114,12 +105,11 @@
     static int applyProxyRules(RTHTTP hHttp, const QString &strHostName, int iPort);
     static int applyRawHeaders(RTHTTP hHttp, const QList<QByteArray> &headers, const QNetworkRequest &request);
-    static bool allCertsFound(uint64_t fFoundCerts, bool fOnlyMandatory);
-    static uint64_t certEntryFoundMask(uint32_t iCert);
-    static bool checkCertificatesInFile(const char *pszCaCertFile);
-    static bool checkCertificatesInStore(RTCRSTORE hStore, unsigned *pcCertificates = NULL);
-    static int downloadCertificates(RTHTTP hHttp, const char *pszCaCertFile);
+    static unsigned countCertsFound(bool const *pafFoundCerts);
+    static bool areAllCertsFound(bool const *pafFoundCerts, bool fOnlyMandatory);
+    static void refreshCertificates(RTHTTP hHttp, RTCRSTORE hOldStore, bool *pafFoundCerts, const char *pszCaCertFile);
+    static void downloadMissingCertificates(RTCRSTORE hNewStore, bool *pafNewFoundCerts, RTHTTP hHttp,
+                                            PRTERRINFOSTATIC pStaticErrInfo);
     static int convertVerifyAndAddPemCertificateToStore(RTCRSTORE hStore, void const *pvResponse,
-                                                        size_t cbResponse, const CERTINFO *pCertInfo);
-    static int retrieveCertificatesFromSystem(const char *pszCaCertFile);
+                                                        size_t cbResponse, PCRTCRCERTWANTED pWantedCert);
     /** @} */
 
@@ -135,5 +125,46 @@
 
     static const QString s_strCertificateFileName;
-    static const CERTINFO s_aCerts[3];
+    static const RTCRCERTWANTED s_aCerts[3];
+    static const CERTINFO s_CertInfoPcaCls3Gen1Md2;
+    static const CERTINFO s_CertInfoPcaCls3Gen1Sha1;
+    static const CERTINFO s_CertInfoPcaCls3Gen5;
+};
+
+/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Sha1 =
+{
+    /*.iAlternativeTo =*/   1,
+    /*.fMandatory     =*/   false,
+    /*.pszZipFile     =*/
+    "VeriSign Root Certificates/Generation 1 (G1) PCAs/Class 3 Public Primary Certification Authority.pem",
+    /*.apszUrls[3]    =*/
+    {
+        "http://www.symantec.com/content/en/us/enterprise/verisign/roots/Class-3-Public-Primary-Certification-Authority.pem",
+        "http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem", /* dead */
+        NULL,
+        "http://update.virtualbox.org/cacerts-symantec-PCA-3-pem-has-gone-missing-again" /* attention getter */
+    }
+};
+
+/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Md2 =
+{
+    /*.iAlternativeTo =*/   0,
+    /*.fMandatory     =*/   false,
+    /*.pszZipFile     =*/   NULL,
+    /*.apszUrls[3]    =*/   { NULL, NULL, NULL },
+};
+
+/*static*/ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen5 =
+{
+    /*.iAlternativeTo =*/   UINT8_MAX,
+    /*.fMandatory     =*/   true,
+    /*.pszZipFile     =*/
+    "VeriSign Root Certificates/Generation 5 (G5) PCA/VeriSign Class 3 Public Primary Certification Authority - G5.pem",
+    /*.apszUrls[3]    =*/
+    {
+        "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem",
+        "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem", /* (in case they correct above typo) */
+        "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem", /* dead */
+        "http://update.virtualbox.org/cacerts-symantec-PCA-3G5-pem-has-gone-missing-again" /* attention getter */
+    }
 };
 
@@ -141,21 +172,21 @@
 /**
  * Details on the certificates we are after.
+ * The pvUser member points to a UINetworkReplyPrivateThread::CERTINFO.
  */
-/* static */ const UINetworkReplyPrivateThread::CERTINFO UINetworkReplyPrivateThread::s_aCerts[3] =
+/* static */ const RTCRCERTWANTED UINetworkReplyPrivateThread::s_aCerts[3] =
 {
     /*[0] =*/   /* The reissued version with the SHA-1 signature. */
 /** @todo r=bird: Why do we need this certificate? Neither update.virtualbox.org nor www.virtualbox.org uses it...  ElCapitan doesn't ship this. */
     {
-        /*.pszSubject =*/
-        "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
-        /*.cbEncoded      =*/   0x240,
-        /*.iAlternativeTo =*/   1,
-        /*.fMandatory     =*/   false,
-        /*.abSha1         =*/
+        /*.pszSubject        =*/    "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
+        /*.cbEncoded         =*/    0x240,
+        /*.Sha1Fingerprint   =*/    true,
+        /*.Sha512Fingerprint =*/    true,
+        /*.abSha1            =*/
         {
             0xa1, 0xdb, 0x63, 0x93, 0x91, 0x6f, 0x17, 0xe4, 0x18, 0x55,
             0x09, 0x40, 0x04, 0x15, 0xc7, 0x02, 0x40, 0xb0, 0xae, 0x6b
         },
-        /*.abSha512       =*/
+        /*.abSha512          =*/
         {
             0xbb, 0xf7, 0x8a, 0x19, 0x9f, 0x37, 0xee, 0xa2,
@@ -168,27 +199,18 @@
             0x0a, 0x67, 0x83, 0x87, 0xc5, 0x45, 0xc4, 0x99
         },
-        /*.pszZipFile     =*/
-        "VeriSign Root Certificates/Generation 1 (G1) PCAs/Class 3 Public Primary Certification Authority.pem",
-        /*.apszUrls[3]    =*/
-        {
-            "http://www.symantec.com/content/en/us/enterprise/verisign/roots/Class-3-Public-Primary-Certification-Authority.pem",
-            "http://www.verisign.com/repository/roots/root-certificates/PCA-3.pem", /* dead */
-            NULL,
-            "http://update.virtualbox.org/cacerts-symantec-PCA-3-pem-has-gone-missing-again" /* attention getter */
-        },
+        /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Sha1
     },
     /*[1] =*/   /* The original version with the MD2 signature. */
     {
-        /*.pszSubject     =*/
-        "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
-        /*.cbEncoded      =*/   0x240,
-        /*.iAlternativeTo =*/   0,
-        /*.fMandatory     =*/   false,
-        /*.abSha1         =*/
+        /*.pszSubject        =*/    "C=US, O=VeriSign, Inc., OU=Class 3 Public Primary Certification Authority",
+        /*.cbEncoded         =*/    0x240,
+        /*.Sha1Fingerprint   =*/    true,
+        /*.Sha512Fingerprint =*/    true,
+        /*.abSha1            =*/
         {
             0x74, 0x2c, 0x31, 0x92, 0xe6, 0x07, 0xe4, 0x24, 0xeb, 0x45,
             0x49, 0x54, 0x2b, 0xe1, 0xbb, 0xc5, 0x3e, 0x61, 0x74, 0xe2
         },
-        /*.abSha512       =*/
+        /*.abSha512          =*/
         {
             0x7c, 0x2f, 0x94, 0x22, 0x5f, 0x67, 0x98, 0x89,
@@ -201,21 +223,20 @@
             0xc8, 0x0c, 0x5a, 0xe7, 0x8b, 0x33, 0xf2, 0xaa
         },
-        /*.pszZipFile     =*/ NULL,
-        /*.apszUrls[3]    =*/ { NULL, NULL, NULL },
+        /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen1Md2
     },
     /*[2] =*/
     {
-        /*.pszSubject =*/
+        /*.pszSubject        =*/
         "C=US, O=VeriSign, Inc., OU=VeriSign Trust Network, OU=(c) 2006 VeriSign, Inc. - For authorized use only, "
         "CN=VeriSign Class 3 Public Primary Certification Authority - G5",
-        /*.cbEncoded      =*/   0x4d7,
-        /*.iAlternativeTo =*/   UINT8_MAX,
-        /*.fMandatory     =*/   true,
-        /*.abSha1         =*/
+        /*.cbEncoded         =*/    0x4d7,
+        /*.Sha1Fingerprint   =*/    true,
+        /*.Sha512Fingerprint =*/    true,
+        /*.abSha1            =*/
         {
             0x4e, 0xb6, 0xd5, 0x78, 0x49, 0x9b, 0x1c, 0xcf, 0x5f, 0x58,
             0x1e, 0xad, 0x56, 0xbe, 0x3d, 0x9b, 0x67, 0x44, 0xa5, 0xe5
         },
-        /*.abSha512   =*/
+        /*.abSha512          =*/
         {
             0xd4, 0xf8, 0x10, 0x54, 0x72, 0x77, 0x0a, 0x2d,
@@ -228,13 +249,5 @@
             0xd2, 0x6b, 0xa8, 0x9a, 0xf0, 0xb3, 0x6a, 0x01
         },
-        /*.pszZipFile     =*/
-        "VeriSign Root Certificates/Generation 5 (G5) PCA/VeriSign Class 3 Public Primary Certification Authority - G5.pem",
-        /*.apszUrls[3]    =*/
-        {
-            "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class%203-Public-Primary-Certification-Authority-G5.pem",
-            "http://www.symantec.com/content/en/us/enterprise/verisign/roots/VeriSign-Class-3-Public-Primary-Certification-Authority-G5.pem", /* (in case they correct above typo) */
-            "http://www.verisign.com/repository/roots/root-certificates/PCA-3G5.pem", /* dead */
-            "http://update.virtualbox.org/cacerts-symantec-PCA-3G5-pem-has-gone-missing-again" /* attention getter */
-        },
+        /*.pvUser */ &UINetworkReplyPrivateThread::s_CertInfoPcaCls3Gen5
     },
 };
@@ -288,24 +301,73 @@
 
     /*
-     * Check that the certificate file is recent and contains the necessary certificates.
+     * Check the state of our CA certificate file, it's one of the following:
+     *      - Missing, recreate from scratch (= refresh).
+     *      - Everything is there and it is less than 28 days old, do nothing.
+     *      - Everything is there but it's older than 28 days, refresh.
+     *      - Missing certificates and is older than 1 min, refresh.
+     *
+     * Start by creating a store for loading the current state into, as we'll
+     * be need that for the refresh.
      */
-    int rc;
-    if (checkCertificatesInFile(pszCaCertFile))
-        rc = RTHttpSetCAFile(m_hHttp, pszCaCertFile);
-    else
-    {
+    RTCRSTORE hCurStore = NIL_RTCRSTORE;
+    int rc = RTCrStoreCreateInMem(&hCurStore, 256);
+    if (RT_SUCCESS(rc))
+    {
+        bool fRefresh    = true;
+        bool afCertsFound[RT_ELEMENTS(s_aCerts)];
+        RT_ZERO(afCertsFound);
+
         /*
-         * Need to create/update the CA certificate file.  Try see if the necessary
-         * certificates are to be found somewhere on the local system, then fall back
-         * to downloading them.
+         * Load the file if it exists.
+         *
+         * To effect regular updates, we need the modification date of the file,
+         * so we use RTPathQueryInfoEx here and not RTFileExists.
          */
-        rc = retrieveCertificatesFromSystem(pszCaCertFile);
-        if (RT_FAILURE(rc))
-            rc = downloadCertificates(m_hHttp, pszCaCertFile);
-
+        RTFSOBJINFO Info;
+        int rc = RTPathQueryInfoEx(pszCaCertFile, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
+        if (   RT_SUCCESS(rc)
+            && RTFS_IS_FILE(Info.Attr.fMode))
+        {
+            RTERRINFOSTATIC StaticErrInfo;
+            rc = RTCrStoreCertAddFromFile(hCurStore, RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR, pszCaCertFile,
+                                          RTErrInfoInitStatic(&StaticErrInfo));
+            if (RTErrInfoIsSet(&StaticErrInfo.Core))
+                LogRel(("checkCertificates: %s\n", StaticErrInfo.Core.pszMsg));
+            else
+                AssertRC(rc);
+
+            /*
+             * Scan the store the for certificates we need, then see what we
+             * need to do wrt file age.
+             */
+            rc = RTCrStoreCertCheckWanted(hCurStore, s_aCerts, RT_ELEMENTS(s_aCerts), afCertsFound);
+            AssertRC(rc);
+            RTTIMESPEC RefreshAge;
+            uint32_t   cSecRefresh = rc == VINF_SUCCESS  ? 28 * RT_SEC_1DAY /* all found */ : 60 /* stuff missing */;
+            fRefresh = RTTimeSpecCompare(&Info.ModificationTime, RTTimeSpecSubSeconds(RTTimeNow(&RefreshAge), cSecRefresh)) <= 0;
+        }
+
+        /*
+         * Refresh the file if necessary.
+         */
+        if (fRefresh)
+            refreshCertificates(m_hHttp, hCurStore, afCertsFound, pszCaCertFile);
+
+        RTCrStoreRelease(hCurStore);
+
+        /*
+         * Final verdict.
+         */
+        if (areAllCertsFound(afCertsFound, true /*fOnlyMandatory*/))
+            rc = VINF_SUCCESS;
+        else
+            rc = VERR_NOT_FOUND; /** @todo r=bird: Why not try and let RTHttpGet* bitch if the necessary certs are missing? */
+
+        /*
+         * Set our custom CA file.
+         */
         if (RT_SUCCESS(rc))
             rc = RTHttpSetCAFile(m_hHttp, pszCaCertFile);
     }
-
     return rc;
 }
@@ -426,57 +488,17 @@
 
 /**
- * Checks if the certificates we desire are all present in the given file, and
- * that the file is recent enough (not for downloaded certs).
+ * Counts the number of certificates found in a search result array.
  *
- * @returns true if fine, false if not.
- * @param   pszCaCertFile   The path to the certificate file.
+ * @returns Number of wanted certifcates we've found.
+ * @param   pafFoundCerts       Array parallel to s_aCerts with the status of
+ *                              each wanted certificate.
  */
-/*static*/ bool
-UINetworkReplyPrivateThread::checkCertificatesInFile(const char *pszCaCertFile)
-{
-    bool fFoundCerts = false;
-
-    /*
-     * Check whether the file exists.
-     */
-    RTFSOBJINFO Info;
-    int rc = RTPathQueryInfoEx(pszCaCertFile, &Info, RTFSOBJATTRADD_NOTHING, RTPATH_F_FOLLOW_LINK);
-    if (   RT_SUCCESS(rc)
-        && RTFS_IS_FILE(Info.Attr.fMode))
-    {
-        /*
-         * Load the CA certificate file into a store and use
-         * checkCertificatesInStore to do the real work.
-         */
-        RTCRSTORE hStore;
-        int rc = RTCrStoreCreateInMem(&hStore, 256);
-        if (RT_SUCCESS(rc))
-        {
-            RTERRINFOSTATIC StaticErrInfo;
-            rc = RTCrStoreCertAddFromFile(hStore, RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR, pszCaCertFile,
-                                          RTErrInfoInitStatic(&StaticErrInfo));
-            if (RTErrInfoIsSet(&StaticErrInfo.Core))
-                LogRel(("checkCertificates: %s\n", StaticErrInfo.Core.pszMsg));
-            else
-                AssertRC(rc);
-
-            unsigned cCertificates = 0;
-            fFoundCerts = checkCertificatesInStore(hStore, &cCertificates);
-
-            RTCrStoreRelease(hStore);
-
-            /*
-             * If there are more than two certificates in the database, we're looking
-             * at a mirror of the system CA stores.  Refresh our snapshot once every 28 days.
-             */
-            RTTIMESPEC MaxAge;
-            if (   fFoundCerts
-                && cCertificates > 2
-                && RTTimeSpecCompare(&Info.ModificationTime, RTTimeSpecSubSeconds(RTTimeNow(&MaxAge), 28 *24*3600)) < 0)
-                fFoundCerts = false;
-        }
-    }
-
-    return fFoundCerts;
+/*static*/ unsigned
+UINetworkReplyPrivateThread::countCertsFound(bool const *pafFoundCerts)
+{
+    unsigned cFound = 0;
+    for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
+        cFound += pafFoundCerts[i];
+    return cFound;
 }
 
@@ -485,6 +507,6 @@
  *
  * @returns true if we have, false if we haven't.
- * @param   fFoundCerts         The mask of found certificates (see
- *                              certEntryFoundMask).
+ * @param   pafFoundCerts       Array parallel to s_aCerts with the status of
+ *                              each wanted certificate.
  * @param   fOnlyMandatory      Only require mandatory certificates to be
  *                              present.  If false, all certificates must be
@@ -492,135 +514,107 @@
  */
 /*static*/ bool
-UINetworkReplyPrivateThread::allCertsFound(uint64_t fFoundCerts, bool fOnlyMandatory)
-{
-    AssertCompile(RT_ELEMENTS(s_aCerts) < 64);
-
-    /* Add non-mandatory flags before comparing. */
-    if (   fOnlyMandatory
-        && fFoundCerts != RT_BIT_64(RT_ELEMENTS(s_aCerts)) - UINT64_C(1))
+UINetworkReplyPrivateThread::areAllCertsFound(bool const *pafFoundCerts, bool fOnlyMandatory)
+{
+    if (fOnlyMandatory)
+    {
         for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
-            if (!s_aCerts[i].fMandatory)
-                fFoundCerts |= RT_BIT_64(i);
-
-    return fFoundCerts == RT_BIT_64(RT_ELEMENTS(s_aCerts)) - UINT64_C(1);
-}
-
-/**
- * Calculates the 64-bit 'found' mask for a certificate entry.
- *
- * @returns 64-bit mask.
- * @param   iCert               The certificate entry.
- */
-/*static*/ uint64_t
-UINetworkReplyPrivateThread::certEntryFoundMask(uint32_t iCert)
-{
-    Assert(iCert < RT_ELEMENTS(s_aCerts));
-    uint64_t fMask = RT_BIT_64(iCert);
-
+            if (   !pafFoundCerts[i]
+                && ((const CERTINFO *)s_aCerts[i].pvUser)->fMandatory)
+                return false;
+    }
+    else
+        for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
+            if (!pafFoundCerts[i])
+                return false;
+    return true;
+}
+
+/*static*/ void
+UINetworkReplyPrivateThread::refreshCertificates(RTHTTP hHttp, RTCRSTORE hOldStore, bool *pafOldFoundCerts,
+                                                 const char *pszCaCertFile)
+{
     /*
-     * Tedium: Also mark certificates that this is an alternative to, we only need
-     *         the public key once.
+     * Collect the standard assortment of SSL certificates.
      */
-    uint8_t iAlt = s_aCerts[iCert].iAlternativeTo;
-    if (iAlt != UINT8_MAX)
-    {
-        unsigned cMax = 10;
-        do
-        {
-            Assert(iAlt < RT_ELEMENTS(s_aCerts));
-            Assert(cMax > 1);
-            Assert(strcmp(s_aCerts[iAlt].pszSubject, s_aCerts[iCert].pszSubject) == 0);
-            fMask |= RT_BIT_64(iAlt);
-            iAlt = s_aCerts[iAlt].iAlternativeTo;
-        } while (iAlt != iCert && cMax-- > 0);
-    }
-
-    return fMask;
-}
-
-/**
- * Checks if the certificates we desire are all present in the given store.
- *
- * @returns true if present, false if not.
- * @param   hStore              The store to examine.
- * @param   pcCertificates      Where to return the number of certificates in
- *                              the store. Optional.
- */
-/* static */ bool
-UINetworkReplyPrivateThread::checkCertificatesInStore(RTCRSTORE hStore, unsigned *pcCertificates /* = NULL*/)
-{
-    if (pcCertificates)
-        *pcCertificates = 0;
-
-    /*
-     * Enumerate the store, checking for the certificates we need.
-     */
-    RTCRSTORECERTSEARCH Search;
-    int rc = RTCrStoreCertFindAll(hStore, &Search);
+    uint32_t  cHint = RTCrStoreCertCount(hOldStore);
+    RTCRSTORE hNewStore;
+    int rc = RTCrStoreCreateInMem(&hNewStore, cHint > 32 && cHint < _32K ? cHint + 16 : 256);
     if (RT_SUCCESS(rc))
     {
-        uint64_t      fFoundCerts   = 0;
-        unsigned      cCertificates = 0;
-        PCRTCRCERTCTX pCertCtx;
-        while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
-        {
-            if (   (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
-                && pCertCtx->cbEncoded > 0
-                && pCertCtx->pCert)
+        RTERRINFOSTATIC StaticErrInfo;
+        rc = RTHttpGatherCaCertsInStore(hNewStore, 0 /*fFlags*/, RTErrInfoInitStatic(&StaticErrInfo));
+        if (RTErrInfoIsSet(&StaticErrInfo.Core))
+            LogRel(("refreshCertificates/#1: %s\n", StaticErrInfo.Core.pszMsg));
+        else
+            AssertLogRelRC(rc);
+
+        if (RT_SUCCESS(rc))
+        {
+            /*
+             * Check and see what we've got.  If we haven't got all we desire,
+             * try add it from the previous store.
+             */
+            bool afNewFoundCerts[RT_ELEMENTS(s_aCerts)];
+            RT_ZERO(afNewFoundCerts); /* paranoia */
+
+            rc = RTCrStoreCertCheckWanted(hNewStore, s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts);
+            AssertLogRelRC(rc);
+            Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/));
+            if (rc != VINF_SUCCESS)
             {
-                cCertificates++;
-
-                /*
-                 * It is a X.509 certificate.  Check if it matches any of those we're looking for.
-                 */
-                for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
-                    if (   pCertCtx->cbEncoded == s_aCerts[i].cbEncoded
-                        && RTCrX509Name_MatchWithString(&pCertCtx->pCert->TbsCertificate.Subject, s_aCerts[i].pszSubject))
-                    {
-                        if (RTSha1Check(pCertCtx->pabEncoded, pCertCtx->cbEncoded, s_aCerts[i].abSha1))
-                        {
-                            if (RTSha512Check(pCertCtx->pabEncoded, pCertCtx->cbEncoded, s_aCerts[i].abSha512))
-                            {
-                                fFoundCerts |= certEntryFoundMask(i);
-                                break;
-                            }
-                        }
-                    }
+                rc = RTCrStoreCertAddWantedFromStore(hNewStore,
+                                                     RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+                                                     hOldStore, s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts);
+                AssertLogRelRC(rc);
+                Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/));
             }
-            RTCrCertCtxRelease(pCertCtx);
+
+            /*
+             * If that didn't help, seek out certificates in more obscure places,
+             * like java, mozilla and mutt.
+             */
+            if (rc != VINF_SUCCESS)
+            {
+                rc = RTCrStoreCertAddWantedFromFishingExpedition(hNewStore,
+                                                                 RTCRCERTCTX_F_ADD_IF_NOT_FOUND
+                                                                 | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+                                                                 s_aCerts, RT_ELEMENTS(s_aCerts), afNewFoundCerts,
+                                                                 RTErrInfoInitStatic(&StaticErrInfo));
+                if (RTErrInfoIsSet(&StaticErrInfo.Core))
+                    LogRel(("refreshCertificates/#2: %s\n", StaticErrInfo.Core.pszMsg));
+                Assert(rc != VINF_SUCCESS || areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/));
+            }
+
+            /*
+             * If that didn't help, try download the certificates.
+             */
+            if (rc != VINF_SUCCESS)
+                downloadMissingCertificates(hNewStore, afNewFoundCerts, hHttp, &StaticErrInfo);
+
+            /*
+             * If we've got the same or better hit rate than the old store,
+             * replace the CA certs file.
+             */
+            if (   areAllCertsFound(afNewFoundCerts, false /*fOnlyMandatory*/)
+                || (   countCertsFound(afNewFoundCerts) >= countCertsFound(pafOldFoundCerts)
+                    &&    areAllCertsFound(afNewFoundCerts, true /*fOnlyMandatory*/)
+                       >= areAllCertsFound(pafOldFoundCerts, true /*fOnlyMandatory*/) ) )
+            {
+                rc = RTCrStoreCertExportAsPem(hNewStore, 0 /*fFlags*/, pszCaCertFile);
+                if (RT_SUCCESS(rc))
+                    memcpy(pafOldFoundCerts, afNewFoundCerts, sizeof(afNewFoundCerts));
+                else
+                    RT_ZERO(pafOldFoundCerts);
+            }
         }
-        int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search); AssertRC(rc2);
-
-        /*
-         * Set the certificate count.
-         */
-        if (pcCertificates)
-            *pcCertificates = cCertificates;
-
-        /*
-         * Did we locate all of them?
-         */
-        if (allCertsFound(fFoundCerts, true /* fOnlyMandatory */)) /** @todo combine the two certificate retrieval approaches */
-            return true;
-    }
-    AssertRC(rc);
-    return false;
-}
-
-/*static*/ int
-UINetworkReplyPrivateThread::downloadCertificates(RTHTTP hHttp, const char *pszCaCertFile)
-{
-    /*
-     * Prepare temporary certificate store.
-     */
-    RTCRSTORE hStore;
-    int rc = RTCrStoreCreateInMem(&hStore, RT_ELEMENTS(s_aCerts));
-    AssertRCReturn(rc, rc);
-
-    /*
-     * Accounts for certificates we've downloaded, verified and added to the store.
-     */
-    uint64_t fFoundCerts = 0;
-    AssertCompile(RT_ELEMENTS(s_aCerts) < 64);
+        RTCrStoreRelease(hNewStore);
+    }
+}
+
+/*static*/ void
+UINetworkReplyPrivateThread::downloadMissingCertificates(RTCRSTORE hNewStore, bool *pafNewFoundCerts, RTHTTP hHttp,
+                                                         PRTERRINFOSTATIC pStaticErrInfo)
+{
+    int rc;
 
     /*
@@ -640,57 +634,60 @@
         {
             for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
-                if (s_aCerts[i].pszZipFile)
+                if (!pafNewFoundCerts[i])
                 {
-                    void  *pvFile;
-                    size_t cbFile;
-                    rc = RTZipPkzipMemDecompress(&pvFile, &cbFile, pvRootsZip, cbRootsZip, s_aCerts[i].pszZipFile);
-                    if (RT_SUCCESS(rc))
+                    CERTINFO const *pInfo = (CERTINFO const *)s_aCerts[i].pvUser;
+                    if (pInfo->pszZipFile)
                     {
-                        rc = convertVerifyAndAddPemCertificateToStore(hStore, pvFile, cbFile, &s_aCerts[i]);
-                        RTMemFree(pvFile);
+                        void  *pvFile;
+                        size_t cbFile;
+                        rc = RTZipPkzipMemDecompress(&pvFile, &cbFile, pvRootsZip, cbRootsZip, pInfo->pszZipFile);
                         if (RT_SUCCESS(rc))
-                            fFoundCerts |= certEntryFoundMask(i);
+                        {
+                            rc = convertVerifyAndAddPemCertificateToStore(hNewStore, pvFile, cbFile, &s_aCerts[i]);
+                            RTMemFree(pvFile);
+                            if (RT_SUCCESS(rc))
+                            {
+                                /*
+                                 * Successfully added. Mark it as found and return if we've got them all.
+                                 */
+                                pafNewFoundCerts[i] = true;
+                                if (areAllCertsFound(pafNewFoundCerts, false /* fOnlyMandatory */))
+                                {
+                                    RTHttpFreeResponse(pvRootsZip);
+                                    return;
+                                }
+                            }
+                        }
                     }
                 }
             RTHttpFreeResponse(pvRootsZip);
-            if (allCertsFound(fFoundCerts, false /* fOnlyMandatory */))
-                break;
         }
     }
 
     /*
-     * Fallback: Try download certificates separately.
+     * Try download certificates separately.
      */
-    if (allCertsFound(fFoundCerts, false /* fOnlyMandatory */))
-        for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
-            if (!(fFoundCerts & RT_BIT_64(i)))
-                for (uint32_t iUrl = 0; iUrl < RT_ELEMENTS(s_aCerts[i].apszUrls); i++)
-                    if (s_aCerts[i].apszUrls[iUrl])
+    for (uint32_t i = 0; i < RT_ELEMENTS(s_aCerts); i++)
+        if (!pafNewFoundCerts[i])
+        {
+            CERTINFO const *pInfo = (CERTINFO const *)s_aCerts[i].pvUser;
+            for (uint32_t iUrl = 0; iUrl < RT_ELEMENTS(pInfo->apszUrls); i++)
+                if (pInfo->apszUrls[iUrl])
+                {
+                    void  *pvResponse;
+                    size_t cbResponse;
+                    rc = RTHttpGetBinary(hHttp, pInfo->apszUrls[iUrl], &pvResponse, &cbResponse);
+                    if (RT_SUCCESS(rc))
                     {
-                        void  *pvResponse;
-                        size_t cbResponse;
-                        rc = RTHttpGetBinary(hHttp, s_aCerts[i].apszUrls[iUrl], &pvResponse, &cbResponse);
+                        rc = convertVerifyAndAddPemCertificateToStore(hNewStore, pvResponse, cbResponse, &s_aCerts[i]);
+                        RTHttpFreeResponse(pvResponse);
                         if (RT_SUCCESS(rc))
                         {
-                            rc = convertVerifyAndAddPemCertificateToStore(hStore, pvResponse, cbResponse, &s_aCerts[i]);
-                            RTHttpFreeResponse(pvResponse);
-                            if (RT_SUCCESS(rc))
-                            {
-                                fFoundCerts |= certEntryFoundMask(i);
-                                break;
-                            }
+                            pafNewFoundCerts[i] = true;
+                            break;
                         }
                     }
-
-    /*
-     * See if we've got the certificates we want, save it we do.
-     */
-    if (allCertsFound(fFoundCerts, true /*fOnlyMandatory*/))
-        rc = RTCrStoreCertExportAsPem(hStore, 0 /*fFlags*/, pszCaCertFile);
-    else if (RT_SUCCESS(rc))
-        rc = VERR_NOT_FOUND;
-
-    RTCrStoreRelease(hStore);
-    return rc;
+                }
+        }
 }
 
@@ -703,5 +700,5 @@
  * @param   pvResponse          The raw PEM certificate file bytes.
  * @param   cbResponse          The number of bytes.
- * @param   pCertInfo           The certificate info (we use hashes and encoded
+ * @param   pWantedCert         The certificate info (we use hashes and encoded
  *                              size).
  */
@@ -709,5 +706,5 @@
 UINetworkReplyPrivateThread::convertVerifyAndAddPemCertificateToStore(RTCRSTORE hStore,
                                                                       void const *pvResponse, size_t cbResponse,
-                                                                      const CERTINFO *pCertInfo)
+                                                                      PCRTCRCERTWANTED pWantedCert)
 {
     /*
@@ -730,8 +727,8 @@
         rc = VERR_NOT_FOUND;
         for (PCRTCRPEMSECTION pCur = pSectionHead; pCur; pCur = pCur->pNext)
-            if (pCur->cbData == pCertInfo->cbEncoded)
+            if (pCur->cbData == pWantedCert->cbEncoded)
             {
-                if (   RTSha1Check(pCur->pbData, pCur->cbData, pCertInfo->abSha1)
-                    && RTSha512Check(pCur->pbData, pCur->cbData, pCertInfo->abSha512))
+                if (   RTSha1Check(pCur->pbData, pCur->cbData, pWantedCert->abSha1)
+                    && RTSha512Check(pCur->pbData, pCur->cbData, pWantedCert->abSha512))
                 {
                     /*
@@ -754,5 +751,5 @@
             else
                 LogRel(("convertVerifyAndAddPemCertificateToStore: cbData=%#zx expected %#zx\n",
-                        pCur->cbData, pCertInfo->cbEncoded));
+                        pCur->cbData, pWantedCert->cbEncoded));
 
         RTCrPemFreeSections(pSectionHead);
@@ -760,55 +757,4 @@
     return rc;
 }
-
-/**
- * Tries to retrieve an up to date list of certificates from the system that
- * includes the necessary certs.
- *
- * @returns IPRT status code, success indicating that we've found what we need.
- * @param   pszCaCertFile           Where to store the certificates.
- */
-/*static*/ int
-UINetworkReplyPrivateThread::retrieveCertificatesFromSystem(const char *pszCaCertFile)
-{
-    /*
-     * Duplicate the user and system stores.
-     */
-    RTERRINFOSTATIC StaticErrInfo;
-    RTCRSTORE hUserStore;
-    int rc = RTCrStoreCreateSnapshotById(&hUserStore, RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES,
-                                         RTErrInfoInitStatic(&StaticErrInfo));
-    if (RT_FAILURE(rc))
-        hUserStore = NIL_RTCRSTORE;
-    if (RTErrInfoIsSet(&StaticErrInfo.Core))
-        LogRel(("retrieveCertificatesFromSystem/#1: %s\n", StaticErrInfo.Core.pszMsg));
-
-    RTCRSTORE hSystemStore;
-    rc = RTCrStoreCreateSnapshotById(&hSystemStore, RTCRSTOREID_SYSTEM_TRUSTED_CAS_AND_CERTIFICATES,
-                                     RTErrInfoInitStatic(&StaticErrInfo));
-    if (RT_FAILURE(rc))
-        hUserStore = NIL_RTCRSTORE;
-    if (RTErrInfoIsSet(&StaticErrInfo.Core))
-        LogRel(("retrieveCertificatesFromSystem/#2: %s\n", StaticErrInfo.Core.pszMsg));
-
-    /*
-     * Merge the two.
-     */
-    int rc2 = RTCrStoreCertAddFromStore(hUserStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
-                                        hSystemStore);
-    AssertRC(rc2);
-    RTCrStoreRelease(hSystemStore);
-    hSystemStore = NIL_RTCRSTORE;
-
-    /*
-     * See if we've got the certificates we want, save it we do.
-     */
-    if (checkCertificatesInStore(hUserStore))
-        rc = RTCrStoreCertExportAsPem(hUserStore, 0 /*fFlags*/, pszCaCertFile);
-    else
-        rc = VERR_NOT_FOUND;
-    RTCrStoreRelease(hUserStore);
-    return rc;
-}
-
 
 
Index: /trunk/src/VBox/Runtime/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/Makefile.kmk	(revision 57612)
+++ /trunk/src/VBox/Runtime/Makefile.kmk	(revision 57613)
@@ -368,8 +368,7 @@
 	common/crypto/store.cpp \
 	common/crypto/store-inmem.cpp \
-	common/crypto/RTCrStoreCertAddFromFile.cpp \
-	common/crypto/RTCrStoreCertAddFromDir.cpp \
-	common/crypto/RTCrStoreCertAddFromStore.cpp \
+	common/crypto/store-cert-add-basic.cpp \
 	common/crypto/RTCrStoreCertAddFromJavaKeyStore.cpp \
+	common/crypto/RTCrStoreCertAddWantedFromFishingExpedition.cpp \
 	common/crypto/RTCrStoreCertExportAsPem.cpp \
 	common/dbg/dbg.cpp \
@@ -465,4 +464,5 @@
 	common/path/RTPathExt.cpp \
 	common/path/RTPathFilename.cpp \
+	common/path/RTPathGlob.cpp \
 	common/path/RTPathHasExt.cpp \
 	common/path/RTPathHasPath.cpp \
Index: unk/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromDir.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromDir.cpp	(revision 57612)
+++ 	(revision )
@@ -1,163 +1,0 @@
-/* $Id$ */
-/** @file
- * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromDir.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#include "internal/iprt.h"
-#include <iprt/crypto/store.h>
-
-#include <iprt/assert.h>
-#include <iprt/dir.h>
-#include <iprt/err.h>
-#include <iprt/path.h>
-#include <iprt/string.h>
-
-
-/**
- * Checks if the directory entry matches the specified suffixes.
- *
- * @returns true on match, false on mismatch.
- * @param   pDirEntry           The directory to check.
- * @param   paSuffixes          The array of suffixes to match against.
- * @param   cSuffixes           The number of suffixes in the array.
- */
-DECLINLINE(bool) rtCrStoreIsSuffixMatch(PCRTDIRENTRY pDirEntry, PCRTSTRTUPLE paSuffixes, size_t cSuffixes)
-{
-    if (cSuffixes == 0)
-        return true;
-
-    size_t const cchName = pDirEntry->cbName;
-    size_t i = cSuffixes;
-    while (i-- > 0)
-        if (   cchName > paSuffixes[i].cch
-            && memcmp(&pDirEntry->szName[cchName - paSuffixes[i].cch], paSuffixes[i].psz, paSuffixes[i].cch) == 0)
-            return true;
-
-    return false;
-}
-
-
-RTDECL(int) RTCrStoreCertAddFromDir(RTCRSTORE hStore, uint32_t fFlags, const char *pszDir,
-                                    PCRTSTRTUPLE paSuffixes, size_t cSuffixes, PRTERRINFO pErrInfo)
-{
-    /*
-     * Validate input.
-     */
-    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
-    size_t i = cSuffixes;
-    while (i-- > 0)
-    {
-        Assert(paSuffixes[i].cch > 0);
-        Assert(strlen(paSuffixes[i].psz) == paSuffixes[i].cch);
-    }
-
-    /*
-     * Prepare for constructing path to the files in the directory, so that we
-     * can open them.
-     */
-    char szPath[RTPATH_MAX];
-    int rc = RTStrCopy(szPath, sizeof(szPath), pszDir);
-    if (RT_SUCCESS(rc))
-    {
-        size_t cchPath = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath));
-        if (cchPath > 0)
-        {
-            size_t const cbFilename = sizeof(szPath) - cchPath;
-
-            /*
-             * Enumerate the directory.
-             */
-            PRTDIR hDir;
-            rc = RTDirOpen(&hDir, pszDir);
-            if (RT_SUCCESS(rc))
-            {
-                for (;;)
-                {
-                    /* Read the next entry. */
-                    union
-                    {
-                        RTDIRENTRY  DirEntry;
-                        uint8_t     ab[RTPATH_MAX];
-                    } u;
-                    size_t cbBuf = sizeof(u);
-                    int rc2 = RTDirRead(hDir, &u.DirEntry, &cbBuf);
-                    if (RT_SUCCESS(rc2))
-                    {
-                        if (   !RTDirEntryIsStdDotLink(&u.DirEntry)
-                            && rtCrStoreIsSuffixMatch(&u.DirEntry, paSuffixes, cSuffixes) )
-                        {
-                            if (u.DirEntry.cbName < cbFilename)
-                            {
-                                memcpy(&szPath[cchPath], u.DirEntry.szName, u.DirEntry.cbName + 1);
-                                rc2 = RTDirQueryUnknownType(szPath, true /*fFollowSymlinks*/, &u.DirEntry.enmType);
-                                if (   RT_SUCCESS(rc2)
-                                    && u.DirEntry.enmType == RTDIRENTRYTYPE_FILE)
-                                {
-                                    /*
-                                     * Add it.
-                                     */
-                                    rc2 = RTCrStoreCertAddFromFile(hStore, fFlags, szPath, pErrInfo);
-                                    if (RT_FAILURE(rc2))
-                                    {
-                                        rc = rc2;
-                                        if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
-                                            break;
-                                    }
-                                }
-                            }
-                            else if (   u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
-                                     || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
-                                     || u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
-                            {
-                                rc = RTErrInfoAddF(pErrInfo, VERR_FILENAME_TOO_LONG,
-                                                   "  Too long filename (%u bytes)", u.DirEntry.cbName);
-                                if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
-                                    break;
-                            }
-                        }
-                    }
-                    else
-                    {
-                        if (rc2 != VERR_NO_MORE_FILES)
-                            rc = RTErrInfoAddF(pErrInfo, rc2, "  RTDirRead failed: %Rrc", rc2);
-                        break;
-                    }
-                }
-
-                RTDirClose(hDir);
-            }
-            else
-                rc = RTErrInfoAddF(pErrInfo, rc, "  RTDirOpen('%s'): %Rrc", pszDir, rc);
-        }
-        else
-            rc = VERR_FILENAME_TOO_LONG;
-    }
-    return rc;
-}
-
-
Index: unk/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromFile.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromFile.cpp	(revision 57612)
+++ 	(revision )
@@ -1,152 +1,0 @@
-/* $Id$ */
-/** @file
- * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromFile.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#include "internal/iprt.h"
-#include <iprt/crypto/store.h>
-
-#include <iprt/assert.h>
-#include <iprt/err.h>
-#include <iprt/file.h>
-#include <iprt/crypto/pem.h>
-
-
-/*********************************************************************************************************************************
-*   Global Variables                                                                                                             *
-*********************************************************************************************************************************/
-/** BEGIN CERTIFICATE / END CERTIFICATE. */
-static RTCRPEMMARKERWORD const g_aWords_Certificate[] =
-{
-    { RT_STR_TUPLE("CERTIFICATE") }
-};
-
-/** BEGIN TRUSTED CERTIFICATE / END TRUSTED CERTIFICATE. */
-static RTCRPEMMARKERWORD const g_aWords_TrustedCertificate[] =
-{
-    { RT_STR_TUPLE("TRUSTED") },
-    { RT_STR_TUPLE("CERTIFICATE") }
-};
-
-/** BEGIN X509 CERTIFICATE / END X509 CERTIFICATE. (old) */
-static RTCRPEMMARKERWORD const g_aWords_X509Certificate[] =
-{
-    { RT_STR_TUPLE("X509") },
-    { RT_STR_TUPLE("CERTIFICATE") }
-};
-
-/**
- * X509 Certificate markers.
- *
- * @remark See crypto/pem/pem.h in OpenSSL for a matching list.
- */
-static RTCRPEMMARKER     const g_aCertificateMarkers[] =
-{
-    { g_aWords_Certificate,         RT_ELEMENTS(g_aWords_Certificate) },
-    { g_aWords_TrustedCertificate,  RT_ELEMENTS(g_aWords_TrustedCertificate) },
-    { g_aWords_X509Certificate,     RT_ELEMENTS(g_aWords_X509Certificate) }
-};
-
-
-#if 0
-RTDECL(int) RTCrX509Certificates_ReadFromFile(const char *pszFilename, uint32_t fFlags,
-                                              PRTCRX509CERTIFICATES pCertificates, PRTERRINFO pErrInfo)
-{
-    AssertReturn(!fFlags, VERR_INVALID_FLAGS);
-    PCRTCRPEMSECTION pSectionHead;
-    int rc = RTCrPemReadFile(pszFilename, 0, g_aCertificateMarkers, RT_ELEMENTS(g_aCertificateMarkers), &pSectionHead, pErrInfo);
-    if (RT_SUCCESS(rc))
-    {
-        pCertificates->Allocation
-
-        PCRTCRPEMSECTION pCurSec = pSectionHead;
-        while (pCurSec)
-        {
-
-            pCurSec = pCurSec->pNext;
-        }
-
-        RTCrPemFreeSections(pSectionHead);
-    }
-    return rc;
-}
-#endif
-
-
-RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
-{
-    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
-
-    size_t      cbContent;
-    void        *pvContent;
-    int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
-    if (RT_SUCCESS(rc))
-    {
-        /*
-         * Is it a java key store file?
-         */
-        if (   cbContent > 32
-            && ((uint32_t const *)pvContent)[0] == RT_H2BE_U32_C(UINT32_C(0xfeedfeed)) /* magic */
-            && ((uint32_t const *)pvContent)[1] == RT_H2BE_U32_C(UINT32_C(0x00000002)) /* version */ )
-            rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
-        /*
-         * No assume PEM or DER encoded binary certificate.
-         */
-        else
-        {
-            PCRTCRPEMSECTION pSectionHead;
-            rc = RTCrPemParseContent(pvContent, cbContent, fFlags, g_aCertificateMarkers, RT_ELEMENTS(g_aCertificateMarkers),
-                                     &pSectionHead, pErrInfo);
-            if (RT_SUCCESS(rc))
-            {
-                PCRTCRPEMSECTION pCurSec = pSectionHead;
-                while (pCurSec)
-                {
-                    int rc2 = RTCrStoreCertAddEncoded(hStore,
-                                                      RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
-                                                      pCurSec->pbData, pCurSec->cbData,
-                                                      !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL);
-                    if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
-                    {
-                        rc = rc2;
-                        if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
-                            break;
-                    }
-                    pCurSec = pCurSec->pNext;
-                }
-
-                RTCrPemFreeSections(pSectionHead);
-            }
-        }
-        RTFileReadAllFree(pvContent, cbContent);
-    }
-    else
-        rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
-    return rc;
-}
-
Index: unk/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromStore.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/crypto/RTCrStoreCertAddFromStore.cpp	(revision 57612)
+++ 	(revision )
@@ -1,72 +1,0 @@
-/* $Id$ */
-/** @file
- * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromStore.
- */
-
-/*
- * Copyright (C) 2006-2015 Oracle Corporation
- *
- * This file is part of VirtualBox Open Source Edition (OSE), as
- * available from http://www.virtualbox.org. This file is free software;
- * you can redistribute it and/or modify it under the terms of the GNU
- * General Public License (GPL) as published by the Free Software
- * Foundation, in version 2 as it comes in the "COPYING" file of the
- * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
- * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
- *
- * The contents of this file may alternatively be used under the terms
- * of the Common Development and Distribution License Version 1.0
- * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
- * VirtualBox OSE distribution, in which case the provisions of the
- * CDDL are applicable instead of those of the GPL.
- *
- * You may elect to license modified versions of this file under the
- * terms and conditions of either the GPL or the CDDL or both.
- */
-
-
-/*********************************************************************************************************************************
-*   Header Files                                                                                                                 *
-*********************************************************************************************************************************/
-#include "internal/iprt.h"
-#include <iprt/crypto/store.h>
-
-#include <iprt/assert.h>
-#include <iprt/err.h>
-
-
-
-RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc)
-{
-    /*
-     * Validate input.
-     */
-    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
-
-    /*
-     * Enumerate all the certificates in the source store, adding them to the destination.
-     */
-    RTCRSTORECERTSEARCH Search;
-    int rc = RTCrStoreCertFindAll(hStoreSrc, &Search);
-    if (RT_SUCCESS(rc))
-    {
-        PCRTCRCERTCTX pCertCtx;
-        while ((pCertCtx = RTCrStoreCertSearchNext(hStoreSrc, &Search)) != NULL)
-        {
-            int rc2 = RTCrStoreCertAddEncoded(hStore, pCertCtx->fFlags | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
-                                              pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL);
-            if (RT_FAILURE(rc2))
-            {
-                rc = rc2;
-                if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
-                    break;
-            }
-            RTCrCertCtxRelease(pCertCtx);
-        }
-
-        int rc2 = RTCrStoreCertSearchDestroy(hStoreSrc, &Search); AssertRC(rc2);
-    }
-    return rc;
-}
-RT_EXPORT_SYMBOL(RTCrStoreCertAddFromStore);
-
Index: /trunk/src/VBox/Runtime/common/crypto/RTCrStoreCertAddWantedFromFishingExpedition.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/crypto/RTCrStoreCertAddWantedFromFishingExpedition.cpp	(revision 57613)
+++ /trunk/src/VBox/Runtime/common/crypto/RTCrStoreCertAddWantedFromFishingExpedition.cpp	(revision 57613)
@@ -0,0 +1,237 @@
+/* $Id$ */
+/** @file
+ * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromFishingExpedition.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/crypto/store.h>
+
+#include <iprt/assert.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+
+#include "x509-internal.h"
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+#ifdef RT_OS_WINDOWS
+# define PREFIX_UNIXROOT  "${SystemDrive}/cygwin"
+#elif defined(RT_OS_OS2)
+# define PREFIX_UNIXROOT  "/@unixroot@"
+#else
+# define PREFIX_UNIXROOT
+#endif
+
+
+/**
+ * Count the number of found certificates.
+ *
+ * @returns Number found.
+ * @param   afFound             Indicator array.
+ * @param   cWanted             Number of wanted certificates.
+ */
+DECLINLINE(size_t) rtCrStoreCountFound(bool const *afFound, size_t cWanted)
+{
+    size_t cFound = 0;
+    while (cWanted-- > 0)
+        if (afFound[cWanted])
+            cFound++;
+    return cFound;
+}
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromFishingExpedition(RTCRSTORE hStore, uint32_t fFlags,
+                                                        PCRTCRCERTWANTED paWanted, size_t cWanted,
+                                                        bool *pafFound, PRTERRINFO pErrInfo)
+{
+    int rc = VINF_SUCCESS;
+    int rc2;
+
+    /*
+     * Validate input.
+     */
+    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+    fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR; /* force these! */
+    AssertReturn(cWanted, VERR_NOT_FOUND);
+    for (uint32_t i = 0; i < cWanted; i++)
+    {
+        AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+        AssertReturn(   paWanted[i].pszSubject
+                     || paWanted[i].fSha1Fingerprint
+                     || paWanted[i].fSha512Fingerprint,
+                     VERR_INVALID_PARAMETER);
+    }
+
+    /*
+     * Make sure we've got a result array.
+     */
+    bool *pafFoundFree = NULL;
+    if (!pafFound)
+    {
+        pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
+        AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
+    }
+
+    /*
+     * Search the user and system stores first.
+     */
+    bool fAllFound = false;
+    RTCRSTORE hTmpStore;
+    for (int iStoreId = RTCRSTOREID_INVALID + 1; iStoreId < RTCRSTOREID_END; iStoreId++)
+    {
+        rc2 = RTCrStoreCreateSnapshotById(&hTmpStore, (RTCRSTOREID)iStoreId, NULL);
+        if (RT_SUCCESS(rc2))
+        {
+            rc2 = RTCrStoreCertAddWantedFromStore(hStore, fFlags, hTmpStore, paWanted, cWanted, pafFound);
+            RTCrStoreRelease(hTmpStore);
+            fAllFound = rc2 == VINF_SUCCESS;
+            if (fAllFound)
+                break;
+        }
+    }
+
+    /*
+     * Search alternative file based stores.
+     */
+    if (!fAllFound)
+    {
+        static const char * const s_apszFiles[] =
+        {
+            PREFIX_UNIXROOT "/usr/share/ca-certificates/trust-source/mozilla.neutral-trust.crt",
+            PREFIX_UNIXROOT "/usr/share/ca-certificates/trust-source/mozilla.trust.crt",
+            PREFIX_UNIXROOT "/usr/share/doc/mutt/samples/ca-bundle.crt",
+            PREFIX_UNIXROOT "/usr/jdk/latest/jre/lib/security/cacerts",
+            PREFIX_UNIXROOT "/usr/share/curl/curl-ca-bundle.crt",
+#ifdef RT_OS_DARWIN
+            "/opt/local/share/curl/curl-ca-bundle.crt",
+            "/Library/Internet Plug-Ins/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts",
+            "/System/Library/Java/Support/CoreDeploy.bundle/Contents/Home/lib/security/cacerts",
+            "/System/Library/Java/Support/CoreDeploy.bundle/Contents/JavaAppletPlugin.plugin/Contents/Home/lib/security/cacerts",
+            "/System/Library/Java/Support/Deploy.bundle/Contents/Home/lib/security/cacerts",
+            "/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/MacOS/itms/java/lib/security/cacerts",
+            "/Applications/Xcode.app/Contents/Applications/Application Loader.app/Contents/itms/java/lib/security/cacerts",
+            "/Applications/Xcode-beta.app/Contents/Applications/Application Loader.app/Contents/itms/java/lib/security/cacerts",
+            "/System/Library/Java/JavaVirtualMachines/*/Contents/Home/lib/security/cacerts",
+#endif
+#ifdef RT_OS_LINUX
+            PREFIX_UNIXROOT "/opt/*/jre/lib/security/cacerts",
+#endif
+#ifdef RT_OS_WINDOWS
+            "${BothProgramFiles}/Git/bin/curl-ca-bundle.crt",
+            "${BothProgramFiles}/Mercurial/hgrc.d/cacert.pem",
+            "${BothProgramFiles}/Java/jre*/lib/security/cacerts",
+            "${BothProgramFiles}/Java/jdk*/jre/lib/security/cacerts",
+            "${BothProgramFiles}/HexChat/cert.pem",
+            "${SystemDrive}/BitNami/*/git/bin/curl-ca-bundle.crt",
+            "${SystemDrive}/BitNami/*/heroku/data/cacert.pem",
+            "${SystemDrive}/BitNami/*/heroku/vendor/gems/excon*/data/cacert.pem",
+            "${SystemDrive}/BitNami/*/php/PEAR/AWSSDKforPHP/lib/requstcore/cacert.pem",
+#endif
+        };
+        for (uint32_t i = 0; i < RT_ELEMENTS(s_apszFiles) && !fAllFound; i++)
+        {
+            PCRTPATHGLOBENTRY pResultHead;
+            rc2 = RTPathGlob(s_apszFiles[i], RTPATHGLOB_F_NO_DIRS, &pResultHead, NULL);
+            if (RT_SUCCESS(rc2))
+            {
+                for (PCRTPATHGLOBENTRY pCur = pResultHead; pCur; pCur = pCur->pNext)
+                {
+                    rc2 = RTCrStoreCertAddWantedFromFile(hStore, fFlags, pCur->szPath, paWanted, cWanted, pafFound, pErrInfo);
+                    fAllFound = rc2 == VINF_SUCCESS;
+                    if (fAllFound)
+                        break;
+                }
+                RTPathGlobFree(pResultHead);
+            }
+        }
+    }
+
+    /*
+     * Search alternative directory based stores.
+     */
+    if (!fAllFound)
+    {
+        static const char * const s_apszFiles[] =
+        {
+            PREFIX_UNIXROOT "/usr/share/ca-certificates/mozilla/",
+#ifdef RT_OS_DARWIN
+            "/System/Library/Frameworks/Ruby.framework/Versions/2.0/usr/lib/ruby/2.0.0/rubygems/ssl_certs/"
+#endif
+#ifdef RT_OS_WINDOWS
+            "${BothProgramFiles}/Git/ssl/certs/",
+            "${BothProgramFiles}/Git/ssl/certs/expired/",
+            "${BothProgramFiles}/Common Files/Apple/Internet Services/security.resources/roots/",
+            "${BothProgramFiles}/Raptr/ca-certs/",
+            "${SystemDrive}/Bitname/*/git/ssl/certs/",
+            "${SystemDrive}/Bitnami/*/git/ssl/certs/expired/",
+#endif
+        };
+        for (uint32_t i = 0; i < RT_ELEMENTS(s_apszFiles) && !fAllFound; i++)
+        {
+            PCRTPATHGLOBENTRY pResultHead;
+            rc2 = RTPathGlob(s_apszFiles[i], RTPATHGLOB_F_ONLY_DIRS, &pResultHead, NULL);
+            if (RT_SUCCESS(rc2))
+            {
+                for (PCRTPATHGLOBENTRY pCur = pResultHead; pCur; pCur = pCur->pNext)
+                {
+                    rc2 = RTCrStoreCertAddWantedFromDir(hStore, fFlags, pCur->szPath, NULL /*paSuffixes*/, 0 /*cSuffixes*/,
+                                                        paWanted, cWanted, pafFound, pErrInfo);
+                    fAllFound = rc2 == VINF_SUCCESS;
+                    if (fAllFound)
+                        break;
+                }
+                RTPathGlobFree(pResultHead);
+            }
+        }
+    }
+
+    /*
+     * If all found, return VINF_SUCCESS, otherwise warn that we didn't find everything.
+     */
+    if (RT_SUCCESS(rc))
+    {
+        size_t cFound = rtCrStoreCountFound(pafFound, cWanted);
+        Assert(cFound == cWanted || fAllFound);
+        if (cFound == cWanted)
+            rc = VINF_SUCCESS;
+        else if (cFound > 0)
+            rc = VWRN_NOT_FOUND;
+        else
+            rc = VERR_NOT_FOUND;
+    }
+
+    if (pafFoundFree)
+        RTMemTmpFree(pafFoundFree);
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromFishingExpedition);
+
+
Index: /trunk/src/VBox/Runtime/common/crypto/store-cert-add-basic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/crypto/store-cert-add-basic.cpp	(revision 57613)
+++ /trunk/src/VBox/Runtime/common/crypto/store-cert-add-basic.cpp	(revision 57613)
@@ -0,0 +1,849 @@
+/* $Id$ */
+/** @file
+ * IPRT - Cryptographic (Certificate) Store, RTCrStoreCertAddFromDir.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/crypto/store.h>
+
+#include <iprt/assert.h>
+#include <iprt/crypto/pem.h>
+#include <iprt/dir.h>
+#include <iprt/err.h>
+#include <iprt/file.h>
+#include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/sha.h>
+#include <iprt/string.h>
+
+#include "x509-internal.h"
+
+
+/*********************************************************************************************************************************
+*   Global Variables                                                                                                             *
+*********************************************************************************************************************************/
+/** BEGIN CERTIFICATE / END CERTIFICATE. */
+static RTCRPEMMARKERWORD const g_aWords_Certificate[] =
+{
+    { RT_STR_TUPLE("CERTIFICATE") }
+};
+
+/** BEGIN TRUSTED CERTIFICATE / END TRUSTED CERTIFICATE. */
+static RTCRPEMMARKERWORD const g_aWords_TrustedCertificate[] =
+{
+    { RT_STR_TUPLE("TRUSTED") },
+    { RT_STR_TUPLE("CERTIFICATE") }
+};
+
+/** BEGIN X509 CERTIFICATE / END X509 CERTIFICATE. (old) */
+static RTCRPEMMARKERWORD const g_aWords_X509Certificate[] =
+{
+    { RT_STR_TUPLE("X509") },
+    { RT_STR_TUPLE("CERTIFICATE") }
+};
+
+/**
+ * X509 Certificate markers.
+ *
+ * @remark See crypto/pem/pem.h in OpenSSL for a matching list.
+ */
+RTCRPEMMARKER const g_aX509CertificateMarkers[3] =
+{
+    { g_aWords_Certificate,         RT_ELEMENTS(g_aWords_Certificate) },
+    { g_aWords_TrustedCertificate,  RT_ELEMENTS(g_aWords_TrustedCertificate) },
+    { g_aWords_X509Certificate,     RT_ELEMENTS(g_aWords_X509Certificate) }
+};
+
+
+
+/**
+ * Checks if we've found all the certificates already.
+ *
+ * @returns true if all found, false if not.
+ * @param   afFound             Indicator array.
+ * @param   cWanted             Number of wanted certificates.
+ */
+DECLINLINE(bool) rtCrStoreAllDone(bool const *afFound, size_t cWanted)
+{
+    while (cWanted-- > 0)
+        if (!afFound[cWanted])
+            return false;
+    return true;
+}
+
+
+/**
+ * Checks if the given certificate specs matches the given wanted poster.
+ *
+ * @returns true if match, false if not.
+ * @param   pWanted     The certificate wanted poster.
+ * @param   cbEncoded   The candidate certificate encoded size.
+ * @param   paSha1      The candidate certificate SHA-1 fingerprint.
+ * @param   paSha512    The candidate certificate SHA-512 fingerprint.
+ * @param   pCert       The decoded candidate certificate, optional.  If not
+ *                      given the result will be uncertain.
+ */
+DECLINLINE(bool) rtCrStoreIsCertEqualToWanted(PCRTCRCERTWANTED pWanted,
+                                              size_t cbEncoded,
+                                              uint8_t const pabSha1[RTSHA1_HASH_SIZE],
+                                              uint8_t const pabSha512[RTSHA512_HASH_SIZE],
+                                              PCRTCRX509CERTIFICATE pCert)
+{
+    if (   pWanted->cbEncoded != cbEncoded
+        && pWanted->cbEncoded != 0)
+        return false;
+
+    if (   pWanted->fSha1Fingerprint
+        && memcmp(pWanted->abSha1, pabSha1, RTSHA1_HASH_SIZE) != 0)
+        return false;
+
+    if (   pWanted->fSha512Fingerprint
+        && memcmp(pWanted->abSha512, pabSha512, RTSHA512_HASH_SIZE) != 0)
+        return false;
+
+    if (   pWanted->pszSubject
+        && pCert
+        && !RTCrX509Name_MatchWithString(&pCert->TbsCertificate.Subject, pWanted->pszSubject))
+        return false;
+
+    return true;
+}
+
+
+/**
+ * Checks if a certificate is wanted.
+ *
+ * @returns true if match, false if not.
+ * @param   paWanted    The certificate wanted posters.
+ * @param   cWanted     The number of wanted posters.
+ * @param   apfFound    Found initicators running paralell to @a paWanted.
+ * @param   cbEncoded   The candidate certificate encoded size.
+ * @param   paSha1      The candidate certificate SHA-1 fingerprint.
+ * @param   paSha512    The candidate certificate SHA-512 fingerprint.
+ * @param   pCert       The decoded candidate certificate, optional.  If not
+ *                      given the result will be uncertain.
+ */
+DECLINLINE(bool) rtCrStoreIsCertWanted(PCRTCRCERTWANTED paWanted, size_t cWanted, bool const *pafFound, size_t cbEncoded,
+                                       uint8_t const pabSha1[RTSHA1_HASH_SIZE], uint8_t const pabSha512[RTSHA512_HASH_SIZE],
+                                       PCRTCRX509CERTIFICATE pCert)
+{
+    for (size_t iCert = 0; iCert < cWanted; iCert++)
+        if (!pafFound[iCert])
+            if (rtCrStoreIsCertEqualToWanted(&paWanted[iCert], cbEncoded, pabSha1, pabSha512, pCert))
+                return true;
+    return false;
+}
+
+
+/**
+ * Marks a certificate as found after it has been added to the store.
+ *
+ * May actually mark several certificates as found if there are duplicates or
+ * ambiguities in the wanted list.
+ *
+ * @returns true if all have been found, false if more to search for.
+ *
+ * @param   apfFound    Found initicators running paralell to @a paWanted.
+ *                      This is what this function updates.
+ * @param   paWanted    The certificate wanted posters.
+ * @param   cWanted     The number of wanted posters.
+ * @param   cbEncoded   The candidate certificate encoded size.
+ * @param   paSha1      The candidate certificate SHA-1 fingerprint.
+ * @param   paSha512    The candidate certificate SHA-512 fingerprint.
+ * @param   pCert       The decoded candidate certificate, optional.  If not
+ *                      given the result will be uncertain.
+ */
+static bool rtCrStoreMarkCertFound(bool *pafFound, PCRTCRCERTWANTED paWanted, size_t cWanted, size_t cbEncoded,
+                                   uint8_t const pabSha1[RTSHA1_HASH_SIZE], uint8_t const pabSha512[RTSHA512_HASH_SIZE],
+                                   PCRTCRX509CERTIFICATE pCert)
+{
+    size_t cFound = 0;
+    for (size_t iCert = 0; iCert < cWanted; iCert++)
+        if (pafFound[iCert])
+            cFound++;
+        else if (rtCrStoreIsCertEqualToWanted(&paWanted[iCert], cbEncoded, pabSha1, pabSha512, pCert))
+        {
+            pafFound[iCert] = true;
+            cFound++;
+        }
+    return cFound == cWanted;
+}
+
+
+RTDECL(int) RTCrStoreCertAddFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hStoreSrc)
+{
+    /*
+     * Validate input.
+     */
+    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+
+    /*
+     * Enumerate all the certificates in the source store, adding them to the destination.
+     */
+    RTCRSTORECERTSEARCH Search;
+    int rc = RTCrStoreCertFindAll(hStoreSrc, &Search);
+    if (RT_SUCCESS(rc))
+    {
+        PCRTCRCERTCTX pCertCtx;
+        while ((pCertCtx = RTCrStoreCertSearchNext(hStoreSrc, &Search)) != NULL)
+        {
+            int rc2 = RTCrStoreCertAddEncoded(hStore, pCertCtx->fFlags | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
+                                              pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL);
+            if (RT_FAILURE(rc2))
+            {
+                rc = rc2;
+                if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+                    break;
+            }
+            RTCrCertCtxRelease(pCertCtx);
+        }
+
+        int rc2 = RTCrStoreCertSearchDestroy(hStoreSrc, &Search); AssertRC(rc2);
+    }
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddFromStore);
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromStore(RTCRSTORE hStore, uint32_t fFlags, RTCRSTORE hSrcStore,
+                                            PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound)
+{
+    /*
+     * Validate input a little.
+     */
+    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+    fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
+
+    AssertReturn(cWanted, VERR_NOT_FOUND);
+    for (uint32_t i = 0; i < cWanted; i++)
+    {
+        AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+        AssertReturn(   paWanted[i].pszSubject
+                     || paWanted[i].fSha1Fingerprint
+                     || paWanted[i].fSha512Fingerprint,
+                     VERR_INVALID_PARAMETER);
+    }
+
+    /*
+     * Make sure we've got a result array.
+     */
+    bool *pafFoundFree = NULL;
+    if (!pafFound)
+    {
+        pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
+        AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
+    }
+
+    /*
+     * Enumerate the store entries.
+     */
+    RTCRSTORECERTSEARCH Search;
+    int rc = RTCrStoreCertFindAll(hSrcStore, &Search);
+    if (RT_SUCCESS(rc))
+    {
+        rc = VWRN_NOT_FOUND;
+        PCRTCRCERTCTX pCertCtx;
+        while ((pCertCtx = RTCrStoreCertSearchNext(hSrcStore, &Search)) != NULL)
+        {
+            if (   (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
+                && pCertCtx->cbEncoded > 0
+                && pCertCtx->pCert)
+            {
+                /*
+                 * If the certificate is wanted, try add it to the store.
+                 */
+                uint8_t abSha1[RTSHA1_HASH_SIZE];
+                RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha1);
+                uint8_t abSha512[RTSHA512_HASH_SIZE];
+                RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha512);
+                if (rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
+                {
+                    int rc2 = RTCrStoreCertAddEncoded(hStore,
+                                                      RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
+                                                      pCertCtx->pabEncoded, pCertCtx->cbEncoded, NULL /*pErrInfo*/);
+                    if (RT_SUCCESS(rc2))
+                    {
+                        /*
+                         * Mark it as found, stop if we've found all.
+                         */
+                        if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted,
+                                                   pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
+                        {
+                            if (RT_SUCCESS(rc))
+                                rc = VINF_SUCCESS;
+                            RTCrCertCtxRelease(pCertCtx);
+                            break;
+                        }
+                    }
+                    else
+                    {
+                        /*
+                         * Some error adding the certificate.  Since it cannot be anything with
+                         * the encoding, it must be something with the store or resources, so
+                         * always return the error status.
+                         */
+                        rc = rc2;
+                        if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+                        {
+                            RTCrCertCtxRelease(pCertCtx);
+                            break;
+                        }
+                    }
+                }
+            }
+            RTCrCertCtxRelease(pCertCtx);
+        }
+        int rc2 = RTCrStoreCertSearchDestroy(hSrcStore, &Search);
+        AssertRC(rc2);
+    }
+
+    if (pafFoundFree)
+        RTMemTmpFree(pafFoundFree);
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromStore);
+
+
+RTDECL(int) RTCrStoreCertCheckWanted(RTCRSTORE hStore, PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound)
+{
+    /*
+     * Validate input a little.
+     */
+    AssertReturn(cWanted, VERR_NOT_FOUND);
+    for (uint32_t i = 0; i < cWanted; i++)
+    {
+        AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+        AssertReturn(   paWanted[i].pszSubject
+                     || paWanted[i].fSha1Fingerprint
+                     || paWanted[i].fSha512Fingerprint,
+                     VERR_INVALID_PARAMETER);
+    }
+    AssertPtrReturn(pafFound, VERR_INVALID_POINTER);
+
+    /*
+     * Clear the found array.
+     */
+    for (uint32_t iCert = 0; iCert < cWanted; iCert++)
+        pafFound[iCert] = false;
+
+    /*
+     * Enumerate the store entries.
+     */
+    RTCRSTORECERTSEARCH Search;
+    int rc = RTCrStoreCertFindAll(hStore, &Search);
+    if (RT_SUCCESS(rc))
+    {
+        rc = VWRN_NOT_FOUND;
+        PCRTCRCERTCTX pCertCtx;
+        while ((pCertCtx = RTCrStoreCertSearchNext(hStore, &Search)) != NULL)
+        {
+            if (   (pCertCtx->fFlags & RTCRCERTCTX_F_ENC_MASK) == RTCRCERTCTX_F_ENC_X509_DER
+                && pCertCtx->cbEncoded > 0
+                && pCertCtx->pCert)
+            {
+                /*
+                 * Hash it and check if it's wanted.  Stop when we've found all.
+                 */
+                uint8_t abSha1[RTSHA1_HASH_SIZE];
+                RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha1);
+                uint8_t abSha512[RTSHA512_HASH_SIZE];
+                RTSha1(pCertCtx->pabEncoded, pCertCtx->cbEncoded, abSha512);
+                if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted, pCertCtx->cbEncoded, abSha1, abSha512, pCertCtx->pCert))
+                {
+                    rc = VINF_SUCCESS;
+                    RTCrCertCtxRelease(pCertCtx);
+                    break;
+                }
+            }
+            RTCrCertCtxRelease(pCertCtx);
+        }
+        int rc2 = RTCrStoreCertSearchDestroy(hStore, &Search);
+        AssertRC(rc2);
+    }
+
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromStore);
+
+
+RTDECL(int) RTCrStoreCertAddFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename, PRTERRINFO pErrInfo)
+{
+    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+
+    size_t      cbContent;
+    void        *pvContent;
+    int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Is it a java key store file?
+         */
+        if (   cbContent > 32
+            && ((uint32_t const *)pvContent)[0] == RT_H2BE_U32_C(UINT32_C(0xfeedfeed)) /* magic */
+            && ((uint32_t const *)pvContent)[1] == RT_H2BE_U32_C(UINT32_C(0x00000002)) /* version */ )
+            rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
+        /*
+         * No assume PEM or DER encoded binary certificate.
+         */
+        else
+        {
+            PCRTCRPEMSECTION pSectionHead;
+            rc = RTCrPemParseContent(pvContent, cbContent,
+                                     (fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)
+                                     ? RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR : 0,
+                                     g_aX509CertificateMarkers, RT_ELEMENTS(g_aX509CertificateMarkers),
+                                     &pSectionHead, pErrInfo);
+            if (RT_SUCCESS(rc))
+            {
+                PCRTCRPEMSECTION pCurSec = pSectionHead;
+                while (pCurSec)
+                {
+                    int rc2 = RTCrStoreCertAddEncoded(hStore,
+                                                      RTCRCERTCTX_F_ENC_X509_DER | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
+                                                      pCurSec->pbData, pCurSec->cbData,
+                                                      !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL);
+                    if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+                    {
+                        rc = rc2;
+                        if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+                            break;
+                    }
+                    pCurSec = pCurSec->pNext;
+                }
+
+                RTCrPemFreeSections(pSectionHead);
+            }
+        }
+        RTFileReadAllFree(pvContent, cbContent);
+    }
+    else
+        rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddFromFile);
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromFile(RTCRSTORE hStore, uint32_t fFlags, const char *pszFilename,
+                                           PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo)
+{
+    /*
+     * Validate input a little.
+     */
+    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+    fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
+
+    AssertReturn(cWanted, VERR_NOT_FOUND);
+    for (uint32_t i = 0; i < cWanted; i++)
+    {
+        AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+        AssertReturn(   paWanted[i].pszSubject
+                     || paWanted[i].fSha1Fingerprint
+                     || paWanted[i].fSha512Fingerprint,
+                     VERR_INVALID_PARAMETER);
+    }
+
+    /*
+     * Make sure we've got a result array.
+     */
+    bool *pafFoundFree = NULL;
+    if (!pafFound)
+    {
+        pafFound = pafFoundFree = (bool *)RTMemTmpAllocZ(sizeof(bool) * cWanted);
+        AssertReturn(pafFound, VERR_NO_TMP_MEMORY);
+    }
+
+    size_t cbContent;
+    void  *pvContent;
+    int rc = RTFileReadAllEx(pszFilename, 0, 64U*_1M, RTFILE_RDALL_O_DENY_WRITE, &pvContent, &cbContent);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Is it a java key store file?   If so, load it into a tmp store
+         * which we can search.  Don't want to duplicate the JKS reader code.
+         */
+        if (   cbContent > 32
+            && ((uint32_t const *)pvContent)[0] == RT_H2BE_U32_C(UINT32_C(0xfeedfeed)) /* magic */
+            && ((uint32_t const *)pvContent)[1] == RT_H2BE_U32_C(UINT32_C(0x00000002)) /* version */ )
+        {
+            RTCRSTORE hTmpStore;
+            rc = RTCrStoreCreateInMem(&hTmpStore, 64);
+            if (RT_SUCCESS(rc))
+            {
+                rc = RTCrStoreCertAddFromJavaKeyStoreInMem(hStore, fFlags, pvContent, cbContent, pszFilename, pErrInfo);
+                if (RT_SUCCESS(rc))
+                    rc = RTCrStoreCertAddWantedFromStore(hStore, fFlags, hTmpStore, paWanted, cWanted, pafFound);
+                RTCrStoreRelease(hTmpStore);
+            }
+            else
+                rc = RTErrInfoSet(pErrInfo, rc, "Error creating temporary crypto store");
+        }
+        /*
+         * No assume PEM or DER encoded binary certificate.  Inspect them one by one.
+         */
+        else
+        {
+            PCRTCRPEMSECTION pSectionHead;
+            rc = RTCrPemParseContent(pvContent, cbContent,
+                                     (fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)
+                                     ? RTCRPEMREADFILE_F_CONTINUE_ON_ENCODING_ERROR : 0,
+                                     g_aX509CertificateMarkers, RT_ELEMENTS(g_aX509CertificateMarkers),
+                                     &pSectionHead, pErrInfo);
+            if (RT_SUCCESS(rc))
+            {
+                rc = VWRN_NOT_FOUND;
+                for (PCRTCRPEMSECTION pCurSec = pSectionHead; pCurSec; pCurSec = pCurSec->pNext)
+                {
+                    if (!pCurSec->cbData)
+                        continue;
+
+                    /*
+                     * See if this is a binary blob we might be interested in.
+                     */
+                    uint8_t abSha1[RTSHA1_HASH_SIZE];
+                    RTSha1(pCurSec->pbData, pCurSec->cbData, abSha1);
+                    uint8_t abSha512[RTSHA512_HASH_SIZE];
+                    RTSha1(pCurSec->pbData, pCurSec->cbData, abSha512);
+                    if (!rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCurSec->cbData, abSha1, abSha512, NULL))
+                        continue;
+
+                    /*
+                     * Decode the certificate so we can match the subject string.
+                     */
+                    RTASN1CURSORPRIMARY Cursor;
+                    RTAsn1CursorInitPrimary(&Cursor, pCurSec->pbData, (uint32_t)pCurSec->cbData,
+                                            !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL,
+                                            &g_RTAsn1DefaultAllocator, RTASN1CURSOR_FLAGS_DER, "InMem");
+                    RTCRX509CERTIFICATE X509Cert;
+                    int rc2 = RTCrX509Certificate_DecodeAsn1(&Cursor.Cursor, 0, &X509Cert, "Cert");
+                    if (RT_SUCCESS(rc2))
+                    {
+                        rc2 = RTCrX509Certificate_CheckSanity(&X509Cert, 0, !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL, "Cert");
+                        if (RT_SUCCESS(rc2))
+                        {
+                            if (rtCrStoreIsCertWanted(paWanted, cWanted, pafFound, pCurSec->cbData, abSha1, abSha512, &X509Cert))
+                            {
+                                /*
+                                 * The certificate is wanted, now add it to the store.
+                                 */
+                                rc2 = RTCrStoreCertAddEncoded(hStore,
+                                                              RTCRCERTCTX_F_ENC_X509_DER
+                                                              | (fFlags & RTCRCERTCTX_F_ADD_IF_NOT_FOUND),
+                                                              pCurSec->pbData, pCurSec->cbData,
+                                                              !RTErrInfoIsSet(pErrInfo) ? pErrInfo : NULL);
+                                if (RT_SUCCESS(rc2))
+                                {
+                                    /*
+                                     * Mark it as found, stop if we've found all.
+                                     */
+                                    if (rtCrStoreMarkCertFound(pafFound, paWanted, cWanted,
+                                                               pCurSec->cbData, abSha1, abSha512, &X509Cert))
+                                    {
+                                        RTAsn1VtDelete(&X509Cert.SeqCore.Asn1Core);
+                                        rc = VINF_SUCCESS;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                        else
+                            Assert(!pErrInfo || RTErrInfoIsSet(pErrInfo));
+                        RTAsn1VtDelete(&X509Cert.SeqCore.Asn1Core);
+                    }
+                    else if (!RTErrInfoIsSet(pErrInfo))
+                        RTErrInfoSetF(pErrInfo, rc2, "RTCrX509Certificate_DecodeAsn1 failed");
+
+                    /*
+                     * Stop on error, if requested.  Otherwise, let pErrInfo keep it.
+                     */
+                    if (RT_FAILURE(rc2) && !(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+                    {
+                        rc = rc2;
+                        break;
+                    }
+                } /* For each PEM section. */
+
+                RTCrPemFreeSections(pSectionHead);
+            }
+        }
+        RTFileReadAllFree(pvContent, cbContent);
+    }
+    else
+        rc = RTErrInfoSetF(pErrInfo, rc, "RTFileReadAllEx failed with %Rrc on '%s'", rc, pszFilename);
+
+    if (pafFoundFree)
+        RTMemTmpFree(pafFoundFree);
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromFile);
+
+
+/**
+ * Checks if the directory entry matches the specified suffixes.
+ *
+ * @returns true on match, false on mismatch.
+ * @param   pDirEntry           The directory to check.
+ * @param   paSuffixes          The array of suffixes to match against.
+ * @param   cSuffixes           The number of suffixes in the array.
+ */
+DECLINLINE(bool) rtCrStoreIsSuffixMatch(PCRTDIRENTRY pDirEntry, PCRTSTRTUPLE paSuffixes, size_t cSuffixes)
+{
+    if (cSuffixes == 0)
+        return true;
+
+    size_t const cchName = pDirEntry->cbName;
+    size_t i = cSuffixes;
+    while (i-- > 0)
+        if (   cchName > paSuffixes[i].cch
+            && memcmp(&pDirEntry->szName[cchName - paSuffixes[i].cch], paSuffixes[i].psz, paSuffixes[i].cch) == 0)
+            return true;
+
+    return false;
+}
+
+
+RTDECL(int) RTCrStoreCertAddFromDir(RTCRSTORE hStore, uint32_t fFlags, const char *pszDir,
+                                    PCRTSTRTUPLE paSuffixes, size_t cSuffixes, PRTERRINFO pErrInfo)
+{
+    /*
+     * Validate input.
+     */
+    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+    size_t i = cSuffixes;
+    while (i-- > 0)
+    {
+        Assert(paSuffixes[i].cch > 0);
+        Assert(strlen(paSuffixes[i].psz) == paSuffixes[i].cch);
+    }
+
+    /*
+     * Prepare for constructing path to the files in the directory, so that we
+     * can open them.
+     */
+    char szPath[RTPATH_MAX];
+    int rc = RTStrCopy(szPath, sizeof(szPath), pszDir);
+    if (RT_SUCCESS(rc))
+    {
+        size_t cchPath = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath));
+        if (cchPath > 0)
+        {
+            size_t const cbMaxFilename = sizeof(szPath) - cchPath;
+
+            /*
+             * Enumerate the directory.
+             */
+            PRTDIR hDir;
+            rc = RTDirOpen(&hDir, pszDir);
+            if (RT_SUCCESS(rc))
+            {
+                for (;;)
+                {
+                    /* Read the next entry. */
+                    union
+                    {
+                        RTDIRENTRY  DirEntry;
+                        uint8_t     ab[RTPATH_MAX];
+                    } u;
+                    size_t cbBuf = sizeof(u);
+                    int rc2 = RTDirRead(hDir, &u.DirEntry, &cbBuf);
+                    if (RT_SUCCESS(rc2))
+                    {
+                        if (   (   u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
+                                || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
+                                || (   u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN
+                                    && !RTDirEntryIsStdDotLink(&u.DirEntry)) )
+                            && rtCrStoreIsSuffixMatch(&u.DirEntry, paSuffixes, cSuffixes) )
+                        {
+                            if (u.DirEntry.cbName < cbMaxFilename)
+                            {
+                                memcpy(&szPath[cchPath], u.DirEntry.szName, u.DirEntry.cbName + 1);
+                                rc2 = RTDirQueryUnknownType(szPath, true /*fFollowSymlinks*/, &u.DirEntry.enmType);
+                                if (   RT_SUCCESS(rc2)
+                                    && u.DirEntry.enmType == RTDIRENTRYTYPE_FILE)
+                                {
+                                    /*
+                                     * Add it.
+                                     */
+                                    rc2 = RTCrStoreCertAddFromFile(hStore, fFlags, szPath, pErrInfo);
+                                    if (RT_FAILURE(rc2))
+                                    {
+                                        rc = rc2;
+                                        if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+                                            break;
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                rc = RTErrInfoAddF(pErrInfo, VERR_FILENAME_TOO_LONG,
+                                                   "  Too long filename (%u bytes)", u.DirEntry.cbName);
+                                if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+                                    break;
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if (rc2 != VERR_NO_MORE_FILES)
+                            rc = RTErrInfoAddF(pErrInfo, rc2, "  RTDirRead failed: %Rrc", rc2);
+                        break;
+                    }
+                }
+
+                RTDirClose(hDir);
+            }
+            else
+                rc = RTErrInfoAddF(pErrInfo, rc, "  RTDirOpen('%s'): %Rrc", pszDir, rc);
+        }
+        else
+            rc = VERR_FILENAME_TOO_LONG;
+    }
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddFromDir);
+
+
+RTDECL(int) RTCrStoreCertAddWantedFromDir(RTCRSTORE hStore, uint32_t fFlags,
+                                          const char *pszDir, PCRTSTRTUPLE paSuffixes, size_t cSuffixes,
+                                          PCRTCRCERTWANTED paWanted, size_t cWanted, bool *pafFound, PRTERRINFO pErrInfo)
+{
+    /*
+     * Validate input a little.
+     */
+    AssertReturn(*pszDir, VERR_PATH_ZERO_LENGTH);
+    AssertReturn(!(fFlags & ~(RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR)), VERR_INVALID_FLAGS);
+    fFlags |= RTCRCERTCTX_F_ADD_IF_NOT_FOUND; /* forced */
+
+    AssertReturn(cWanted, VERR_NOT_FOUND);
+    for (uint32_t i = 0; i < cWanted; i++)
+    {
+        AssertReturn(!paWanted[i].pszSubject || *paWanted[i].pszSubject, VERR_INVALID_PARAMETER);
+        AssertReturn(   paWanted[i].pszSubject
+                     || paWanted[i].fSha1Fingerprint
+                     || paWanted[i].fSha512Fingerprint,
+                     VERR_INVALID_PARAMETER);
+    }
+
+    /*
+     * Prepare for constructing path to the files in the directory, so that we
+     * can open them.
+     */
+    char szPath[RTPATH_MAX];
+    int rc = RTStrCopy(szPath, sizeof(szPath), pszDir);
+    if (RT_SUCCESS(rc))
+    {
+        size_t cchPath = RTPathEnsureTrailingSeparator(szPath, sizeof(szPath));
+        if (cchPath > 0)
+        {
+            size_t const cbMaxFilename = sizeof(szPath) - cchPath;
+
+            /*
+             * Enumerate the directory.
+             */
+            PRTDIR hDir;
+            rc = RTDirOpen(&hDir, pszDir);
+            if (RT_SUCCESS(rc))
+            {
+                rc = VWRN_NOT_FOUND;
+                for (;;)
+                {
+                    /* Read the next entry. */
+                    union
+                    {
+                        RTDIRENTRY  DirEntry;
+                        uint8_t     abPadding[RT_OFFSETOF(RTDIRENTRY, szName) + RTPATH_MAX];
+                    } u;
+                    size_t cbEntry = sizeof(u);
+                    int rc2 = RTDirRead(hDir, &u.DirEntry, &cbEntry);
+                    if (RT_SUCCESS(rc2))
+                    {
+                        if (   (   u.DirEntry.enmType == RTDIRENTRYTYPE_FILE
+                                || u.DirEntry.enmType == RTDIRENTRYTYPE_SYMLINK
+                                || (   u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN
+                                    && !RTDirEntryIsStdDotLink(&u.DirEntry)) )
+                            && rtCrStoreIsSuffixMatch(&u.DirEntry, paSuffixes, cSuffixes) )
+                        {
+                            if (u.DirEntry.cbName < cbMaxFilename)
+                            {
+                                memcpy(&szPath[cchPath], u.DirEntry.szName, u.DirEntry.cbName);
+                                szPath[cchPath + u.DirEntry.cbName] = '\0';
+                                if (u.DirEntry.enmType != RTDIRENTRYTYPE_FILE)
+                                    RTDirQueryUnknownType(szPath, true /*fFollowSymlinks*/, &u.DirEntry.enmType);
+                                if (u.DirEntry.enmType == RTDIRENTRYTYPE_FILE)
+                                {
+                                    rc2 = RTCrStoreCertAddWantedFromFile(hStore, fFlags, szPath,
+                                                                         paWanted, cWanted, pafFound, pErrInfo);
+                                    if (rc2 == VINF_SUCCESS)
+                                    {
+                                        Assert(rtCrStoreAllDone(pafFound, cWanted));
+                                        if (RT_SUCCESS(rc))
+                                            rc = VINF_SUCCESS;
+                                        break;
+                                    }
+                                    if (RT_FAILURE(rc2) && !(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+                                    {
+                                        rc = rc2;
+                                        break;
+                                    }
+                                }
+                            }
+                            else
+                            {
+                                /*
+                                 * pErrInfo keeps the status code unless it's fatal.
+                                 */
+                                RTErrInfoAddF(pErrInfo, VERR_FILENAME_TOO_LONG,
+                                              "  Too long filename (%u bytes)", u.DirEntry.cbName);
+                                if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+                                {
+                                    rc = VERR_FILENAME_TOO_LONG;
+                                    break;
+                                }
+                            }
+                        }
+                    }
+                    else
+                    {
+                        if (rc2 != VERR_NO_MORE_FILES)
+                        {
+                            RTErrInfoAddF(pErrInfo, rc2, "RTDirRead failed: %Rrc", rc2);
+                            if (!(fFlags & RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR))
+                                rc = rc2;
+                        }
+                        break;
+                    }
+                }
+                RTDirClose(hDir);
+            }
+        }
+        else
+            rc = VERR_FILENAME_TOO_LONG;
+    }
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTCrStoreCertAddWantedFromDir);
+
Index: /trunk/src/VBox/Runtime/common/crypto/store.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/crypto/store.cpp	(revision 57612)
+++ /trunk/src/VBox/Runtime/common/crypto/store.cpp	(revision 57613)
@@ -288,4 +288,27 @@
 
 
+RTDECL(uint32_t) RTCrStoreCertCount(RTCRSTORE hStore)
+{
+    PRTCRSTOREINT pThis = (PRTCRSTOREINT)hStore;
+    AssertPtrReturn(pThis, UINT32_MAX);
+    AssertReturn(pThis->u32Magic == RTCRSTOREINT_MAGIC, UINT32_MAX);
+
+    RTCRSTORECERTSEARCH Search;
+    int rc = pThis->pProvider->pfnCertFindAll(pThis->pvProvider, &Search);
+    AssertRCReturn(rc, UINT32_MAX);
+
+
+    uint32_t cCerts = 0;
+    PCRTCRCERTCTX pCur;
+    while ((pCur = pThis->pProvider->pfnCertSearchNext(pThis->pvProvider, &Search)) != NULL)
+    {
+        RTCrCertCtxRelease(pCur);
+        cCerts++;
+    }
+
+    return cCerts;
+}
+
+
 #ifdef IPRT_WITH_OPENSSL
 /*
Index: /trunk/src/VBox/Runtime/common/crypto/x509-internal.h
===================================================================
--- /trunk/src/VBox/Runtime/common/crypto/x509-internal.h	(revision 57612)
+++ /trunk/src/VBox/Runtime/common/crypto/x509-internal.h	(revision 57613)
@@ -29,4 +29,7 @@
 #define ___common_crypto_x509_internal_h
 
+#include <iprt/crypto/pem.h>
+extern RTCRPEMMARKER const g_aX509CertificateMarkers[3];
+
 #define RTASN1TMPL_TEMPLATE_FILE "../common/crypto/x509-template.h"
 #include <iprt/asn1-generator-internal-header.h>
Index: /trunk/src/VBox/Runtime/common/misc/http.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/misc/http.cpp	(revision 57612)
+++ /trunk/src/VBox/Runtime/common/misc/http.cpp	(revision 57613)
@@ -32,14 +32,18 @@
 #include "internal/iprt.h"
 
+#include <iprt/asm.h>
 #include <iprt/assert.h>
+#include <iprt/crypto/store.h>
 #include <iprt/env.h>
 #include <iprt/err.h>
+#include <iprt/file.h>
 #include <iprt/mem.h>
+#include <iprt/path.h>
+#include <iprt/stream.h>
 #include <iprt/string.h>
-#include <iprt/file.h>
-#include <iprt/stream.h>
+
+#include "internal/magics.h"
 
 #include <curl/curl.h>
-#include "internal/magics.h"
 
 
@@ -47,4 +51,7 @@
 *   Structures and Typedefs                                                                                                      *
 *********************************************************************************************************************************/
+/**
+ * Internal HTTP client instance.
+ */
 typedef struct RTHTTPINTERNAL
 {
@@ -52,24 +59,43 @@
     uint32_t            u32Magic;
     /** cURL handle. */
-    CURL                *pCurl;
+    CURL               *pCurl;
     /** The last response code. */
     long                lLastResp;
-    /** custom headers */
-    struct curl_slist   *pHeaders;
-    /** CA certificate for HTTPS authentication check. */
-    char                *pcszCAFile;
+    /** Custom headers/ */
+    struct curl_slist  *pHeaders;
+    /** CA certificate file for HTTPS authentication. */
+    char               *pszCaFile;
+    /** Whether to delete the CA on destruction. */
+    bool                fDeleteCaFile;
     /** Abort the current HTTP request if true. */
-    bool                fAbort;
+    bool volatile       fAbort;
+    /** Set if someone is preforming an HTTP operation. */
+    bool volatile       fBusy;
     /** The location field for 301 responses. */
-    char                *pszRedirLocation;
+    char               *pszRedirLocation;
+
+    /** Output callback data. */
+    union
+    {
+        /** For file destination.  */
+        RTFILE          hFile;
+        /** For memory destination. */
+        struct
+        {
+            /** The current size (sans terminator char). */
+            size_t      cb;
+            /** The currently allocated size. */
+            size_t      cbAllocated;
+            /** Pointer to the buffer. */
+            uint8_t    *pb;
+        } Mem;
+    } Output;
+    /** Output callback status. */
+    int                 rcOutput;
+    /** Download size hint set by the progress callback. */
+    uint64_t            cbDownloadHint;
 } RTHTTPINTERNAL;
+/** Pointer to an internal HTTP client instance. */
 typedef RTHTTPINTERNAL *PRTHTTPINTERNAL;
-
-typedef struct RTHTTPMEMCHUNK
-{
-    uint8_t    *pu8Mem;
-    size_t      cb;
-} RTHTTPMEMCHUNK;
-typedef RTHTTPMEMCHUNK *PRTHTTPMEMCHUNK;
 
 
@@ -77,5 +103,19 @@
 *   Defined Constants And Macros                                                                                                 *
 *********************************************************************************************************************************/
-#define CURL_FAILED(rcCurl) (RT_UNLIKELY(rcCurl != CURLE_OK))
+/** @def RTHTTP_MAX_MEM_DOWNLOAD
+ * The max size we are allowed to download to a memory buffer.
+ *
+ * @remarks The minus 1 is for the trailing zero terminator we always add.
+ */
+#if ARCH_BITS == 64
+# define RTHTTP_MAX_MEM_DOWNLOAD_SIZE       (UINT32_C(64)*_1M - 1)
+#else
+# define RTHTTP_MAX_MEM_DOWNLOAD_SIZE       (UINT32_C(32)*_1M - 1)
+#endif
+
+/** Checks whether a cURL return code indicates success. */
+#define CURL_SUCCESS(rcCurl)    RT_LIKELY(rcCurl == CURLE_OK)
+/** Checks whether a cURL return code indicates failure. */
+#define CURL_FAILURE(rcCurl)    RT_UNLIKELY(rcCurl != CURLE_OK)
 
 /** Validates a handle and returns VERR_INVALID_HANDLE if not valid. */
@@ -97,24 +137,79 @@
 
 
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+static void rtHttpUnsetCaFile(PRTHTTPINTERNAL pThis);
+
+
 RTR3DECL(int) RTHttpCreate(PRTHTTP phHttp)
 {
     AssertPtrReturn(phHttp, VERR_INVALID_PARAMETER);
 
+    /** @todo r=bird: rainy day: curl_global_init is not thread safe, only a
+     *        problem if multiple threads get here at the same time. */
+    int rc = VERR_HTTP_INIT_FAILED;
     CURLcode rcCurl = curl_global_init(CURL_GLOBAL_ALL);
-    if (CURL_FAILED(rcCurl))
-        return VERR_HTTP_INIT_FAILED;
-
-    CURL *pCurl = curl_easy_init();
-    if (!pCurl)
-        return VERR_HTTP_INIT_FAILED;
-
-    PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
-    if (!pHttpInt)
-        return VERR_NO_MEMORY;
-
-    pHttpInt->u32Magic = RTHTTP_MAGIC;
-    pHttpInt->pCurl = pCurl;
-
-    *phHttp = (RTHTTP)pHttpInt;
+    if (!CURL_FAILURE(rcCurl))
+    {
+        CURL *pCurl = curl_easy_init();
+        if (pCurl)
+        {
+            PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)RTMemAllocZ(sizeof(RTHTTPINTERNAL));
+            if (pThis)
+            {
+                pThis->u32Magic = RTHTTP_MAGIC;
+                pThis->pCurl    = pCurl;
+
+                *phHttp = (RTHTTP)pThis;
+
+                return VINF_SUCCESS;
+            }
+            rc = VERR_NO_MEMORY;
+        }
+        else
+            rc = VERR_HTTP_INIT_FAILED;
+    }
+    curl_global_cleanup();
+    return rc;
+}
+
+
+RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
+{
+    if (hHttp == NIL_RTHTTP)
+        return;
+
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN_VOID(pThis);
+
+    Assert(!pThis->fBusy);
+
+    pThis->u32Magic = RTHTTP_MAGIC_DEAD;
+
+    curl_easy_cleanup(pThis->pCurl);
+    pThis->pCurl = NULL;
+
+    if (pThis->pHeaders)
+        curl_slist_free_all(pThis->pHeaders);
+
+    rtHttpUnsetCaFile(pThis);
+    Assert(!pThis->pszCaFile);
+
+    if (pThis->pszRedirLocation)
+        RTStrFree(pThis->pszRedirLocation);
+
+    RTMemFree(pThis);
+
+    curl_global_cleanup();
+}
+
+
+RTR3DECL(int) RTHttpAbort(RTHTTP hHttp)
+{
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN(pThis);
+
+    pThis->fAbort = true;
 
     return VINF_SUCCESS;
@@ -122,77 +217,14 @@
 
 
-RTR3DECL(void) RTHttpDestroy(RTHTTP hHttp)
-{
-    if (!hHttp)
-        return;
-
-    PRTHTTPINTERNAL pHttpInt = hHttp;
-    RTHTTP_VALID_RETURN_VOID(pHttpInt);
-
-    pHttpInt->u32Magic = RTHTTP_MAGIC_DEAD;
-
-    curl_easy_cleanup(pHttpInt->pCurl);
-
-    if (pHttpInt->pHeaders)
-        curl_slist_free_all(pHttpInt->pHeaders);
-
-    if (pHttpInt->pcszCAFile)
-        RTStrFree(pHttpInt->pcszCAFile);
-
-    if (pHttpInt->pszRedirLocation)
-        RTStrFree(pHttpInt->pszRedirLocation);
-
-    RTMemFree(pHttpInt);
-
-    curl_global_cleanup();
-}
-
-
-static DECLCALLBACK(size_t) rtHttpWriteData(void *pvBuf, size_t cb, size_t n, void *pvUser)
-{
-    PRTHTTPMEMCHUNK pMem = (PRTHTTPMEMCHUNK)pvUser;
-    size_t cbAll = cb * n;
-
-    pMem->pu8Mem = (uint8_t*)RTMemRealloc(pMem->pu8Mem, pMem->cb + cbAll + 1);
-    if (pMem->pu8Mem)
-    {
-        memcpy(&pMem->pu8Mem[pMem->cb], pvBuf, cbAll);
-        pMem->cb += cbAll;
-        pMem->pu8Mem[pMem->cb] = '\0';
-    }
-    return cbAll;
-}
-
-
-static DECLCALLBACK(int) rtHttpProgress(void *pData, double DlTotal, double DlNow, double UlTotal, double UlNow)
-{
-    PRTHTTPINTERNAL pHttpInt = (PRTHTTPINTERNAL)pData;
-    AssertReturn(pHttpInt->u32Magic == RTHTTP_MAGIC, 1);
-
-    return pHttpInt->fAbort ? 1 : 0;
-}
-
-
-RTR3DECL(int) RTHttpAbort(RTHTTP hHttp)
-{
-    PRTHTTPINTERNAL pHttpInt = hHttp;
-    RTHTTP_VALID_RETURN(pHttpInt);
-
-    pHttpInt->fAbort = true;
-
-    return VINF_SUCCESS;
-}
-
-
 RTR3DECL(int) RTHttpGetRedirLocation(RTHTTP hHttp, char **ppszRedirLocation)
 {
-    PRTHTTPINTERNAL pHttpInt = hHttp;
-    RTHTTP_VALID_RETURN(pHttpInt);
-
-    if (!pHttpInt->pszRedirLocation)
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN(pThis);
+    Assert(!pThis->fBusy);
+
+    if (!pThis->pszRedirLocation)
         return VERR_HTTP_NOT_FOUND;
 
-    *ppszRedirLocation = RTStrDup(pHttpInt->pszRedirLocation);
-    return VINF_SUCCESS;
+    return RTStrDupEx(ppszRedirLocation, pThis->pszRedirLocation);
 }
 
@@ -200,6 +232,6 @@
 RTR3DECL(int) RTHttpUseSystemProxySettings(RTHTTP hHttp)
 {
-    PRTHTTPINTERNAL pHttpInt = hHttp;
-    RTHTTP_VALID_RETURN(pHttpInt);
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN(pThis);
 
     /*
@@ -213,15 +245,15 @@
         if (!strncmp(szProxy, RT_STR_TUPLE("http://")))
         {
-            rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
-            if (CURL_FAILED(rcCurl))
+            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
+            if (CURL_FAILURE(rcCurl))
                 return VERR_INVALID_PARAMETER;
-            rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, 80);
-            if (CURL_FAILED(rcCurl))
+            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, 80);
+            if (CURL_FAILURE(rcCurl))
                 return VERR_INVALID_PARAMETER;
         }
         else
         {
-            rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
-            if (CURL_FAILED(rcCurl))
+            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, &szProxy[sizeof("http://") - 1]);
+            if (CURL_FAILURE(rcCurl))
                 return VERR_INVALID_PARAMETER;
         }
@@ -237,16 +269,16 @@
                              const char *pcszProxyUser, const char *pcszProxyPwd)
 {
-    PRTHTTPINTERNAL pHttpInt = hHttp;
-    RTHTTP_VALID_RETURN(pHttpInt);
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN(pThis);
     AssertPtrReturn(pcszProxy, VERR_INVALID_PARAMETER);
 
-    int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXY, pcszProxy);
-    if (CURL_FAILED(rcCurl))
+    int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXY, pcszProxy);
+    if (CURL_FAILURE(rcCurl))
         return VERR_INVALID_PARAMETER;
 
     if (uPort != 0)
     {
-        rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPORT, (long)uPort);
-        if (CURL_FAILED(rcCurl))
+        rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPORT, (long)uPort);
+        if (CURL_FAILURE(rcCurl))
             return VERR_INVALID_PARAMETER;
     }
@@ -254,10 +286,10 @@
     if (pcszProxyUser && pcszProxyPwd)
     {
-        rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
-        if (CURL_FAILED(rcCurl))
+        rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYUSERNAME, pcszProxyUser);
+        if (CURL_FAILURE(rcCurl))
             return VERR_INVALID_PARAMETER;
 
-        rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
-        if (CURL_FAILED(rcCurl))
+        rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROXYPASSWORD, pcszProxyPwd);
+        if (CURL_FAILURE(rcCurl))
             return VERR_INVALID_PARAMETER;
     }
@@ -269,12 +301,12 @@
 RTR3DECL(int) RTHttpSetHeaders(RTHTTP hHttp, size_t cHeaders, const char * const *papszHeaders)
 {
-    PRTHTTPINTERNAL pHttpInt = hHttp;
-    RTHTTP_VALID_RETURN(pHttpInt);
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN(pThis);
 
     if (!cHeaders)
     {
-        if (pHttpInt->pHeaders)
-            curl_slist_free_all(pHttpInt->pHeaders);
-        pHttpInt->pHeaders = 0;
+        if (pThis->pHeaders)
+            curl_slist_free_all(pThis->pHeaders);
+        pThis->pHeaders = 0;
         return VINF_SUCCESS;
     }
@@ -284,7 +316,7 @@
         pHeaders = curl_slist_append(pHeaders, papszHeaders[i]);
 
-    pHttpInt->pHeaders = pHeaders;
-    int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_HTTPHEADER, pHeaders);
-    if (CURL_FAILED(rcCurl))
+    pThis->pHeaders = pHeaders;
+    int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_HTTPHEADER, pHeaders);
+    if (CURL_FAILURE(rcCurl))
         return VERR_INVALID_PARAMETER;
 
@@ -293,17 +325,155 @@
 
 
-RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pcszCAFile)
-{
-    PRTHTTPINTERNAL pHttpInt = hHttp;
-    RTHTTP_VALID_RETURN(pHttpInt);
-
-    if (pHttpInt->pcszCAFile)
-        RTStrFree(pHttpInt->pcszCAFile);
-    pHttpInt->pcszCAFile = RTStrDup(pcszCAFile);
-    if (!pHttpInt->pcszCAFile)
-        return VERR_NO_MEMORY;
-
+/**
+ * Set the CA file to NULL, deleting any temporary file if necessary.
+ *
+ * @param   pThis           The HTTP/HTTPS client instance.
+ */
+static void rtHttpUnsetCaFile(PRTHTTPINTERNAL pThis)
+{
+    if (pThis->pszCaFile)
+    {
+        if (pThis->fDeleteCaFile)
+        {
+            int rc2 = RTFileDelete(pThis->pszCaFile);
+            AssertMsg(RT_SUCCESS(rc2) || !RTFileExists(pThis->pszCaFile), ("rc=%Rrc '%s'\n", rc2, pThis->pszCaFile));
+        }
+        RTStrFree(pThis->pszCaFile);
+        pThis->pszCaFile = NULL;
+    }
+}
+
+
+RTR3DECL(int) RTHttpSetCAFile(RTHTTP hHttp, const char *pszCaFile)
+{
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN(pThis);
+
+    rtHttpUnsetCaFile(pThis);
+
+    pThis->fDeleteCaFile = false;
+    if (pszCaFile)
+        return RTStrDupEx(&pThis->pszCaFile, pszCaFile);
     return VINF_SUCCESS;
 }
+
+
+RTR3DECL(int) RTHttpUseTemporaryCaFile(RTHTTP hHttp, PRTERRINFO pErrInfo)
+{
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN(pThis);
+
+    /*
+     * Create a temporary file.
+     */
+    int rc = VERR_NO_STR_MEMORY;
+    char *pszCaFile = RTStrAlloc(RTPATH_MAX);
+    if (pszCaFile)
+    {
+        RTFILE hFile;
+        rc = RTFileOpenTemp(&hFile, pszCaFile, RTPATH_MAX,
+                            RTFILE_O_CREATE | RTFILE_O_WRITE | RTFILE_O_DENY_NONE | (0600 << RTFILE_O_CREATE_MODE_SHIFT));
+        if (RT_SUCCESS(rc))
+        {
+            /*
+             * Gather certificates into a temporary store and export them to the temporary file.
+             */
+            RTCRSTORE hStore;
+            rc = RTCrStoreCreateInMem(&hStore, 256);
+            if (RT_SUCCESS(rc))
+            {
+                rc = RTHttpGatherCaCertsInStore(hStore, 0 /*fFlags*/, pErrInfo);
+                if (RT_SUCCESS(rc))
+                    /** @todo Consider adding an API for exporting to a RTFILE... */
+                    rc = RTCrStoreCertExportAsPem(hStore, 0 /*fFlags*/, pszCaFile);
+                RTCrStoreRelease(hStore);
+            }
+            RTFileClose(hFile);
+            if (RT_SUCCESS(rc))
+            {
+                /*
+                 * Set the CA file for the instance.
+                 */
+                rtHttpUnsetCaFile(pThis);
+
+                pThis->fDeleteCaFile = true;
+                pThis->pszCaFile = pszCaFile;
+                return VINF_SUCCESS;
+            }
+
+            int rc2 = RTFileDelete(pszCaFile);
+            AssertRC(rc2);
+        }
+        else
+            RTErrInfoAddF(pErrInfo, rc, "Error creating temorary file: %Rrc", rc);
+
+        RTStrFree(pszCaFile);
+    }
+    return rc;
+}
+
+
+RTR3DECL(int) RTHttpGatherCaCertsInStore(RTCRSTORE hStore, uint32_t fFlags, PRTERRINFO pErrInfo)
+{
+    uint32_t const cBefore = RTCrStoreCertCount(hStore);
+    AssertReturn(cBefore != UINT32_MAX, VERR_INVALID_HANDLE);
+
+    /*
+     * Add the user store, quitely ignoring any errors.
+     */
+    RTCRSTORE hSrcStore;
+    int rcUser = RTCrStoreCreateSnapshotById(&hSrcStore, RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES, pErrInfo);
+    if (RT_SUCCESS(rcUser))
+    {
+        rcUser = RTCrStoreCertAddFromStore(hStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+                                           hSrcStore);
+        RTCrStoreRelease(hSrcStore);
+    }
+
+    /*
+     * Ditto for the system store.
+     */
+    int rcSystem = RTCrStoreCreateSnapshotById(&hSrcStore, RTCRSTOREID_USER_TRUSTED_CAS_AND_CERTIFICATES, pErrInfo);
+    if (RT_SUCCESS(rcSystem))
+    {
+        rcSystem = RTCrStoreCertAddFromStore(hStore, RTCRCERTCTX_F_ADD_IF_NOT_FOUND | RTCRCERTCTX_F_ADD_CONTINUE_ON_ERROR,
+                                             hSrcStore);
+        RTCrStoreRelease(hSrcStore);
+    }
+
+    /*
+     * If the number of certificates increased, we consider it a success.
+     */
+    if (RTCrStoreCertCount(hStore) > cBefore)
+    {
+        if (RT_FAILURE(rcSystem))
+            return -rcSystem;
+        if (RT_FAILURE(rcUser))
+            return -rcUser;
+        return rcSystem != VINF_SUCCESS ? rcSystem : rcUser;
+    }
+
+    if (RT_FAILURE(rcSystem))
+        return rcSystem;
+    if (RT_FAILURE(rcUser))
+        return rcSystem;
+    return VERR_NOT_FOUND;
+}
+
+
+RTR3DECL(int) RTHttpGatherCaCertsInFile(const char *pszCaFile, uint32_t fFlags, PRTERRINFO pErrInfo)
+{
+    RTCRSTORE hStore;
+    int rc = RTCrStoreCreateInMem(&hStore, 256);
+    if (RT_SUCCESS(rc))
+    {
+        rc = RTHttpGatherCaCertsInStore(hStore, fFlags, pErrInfo);
+        if (RT_SUCCESS(rc))
+            rc = RTCrStoreCertExportAsPem(hStore, 0 /*fFlags*/, pszCaFile);
+        RTCrStoreRelease(hStore);
+    }
+    return rc;
+}
+
 
 
@@ -312,20 +482,20 @@
  *
  * @returns IPRT status code.
- * @param   pHttpInt            HTTP instance.
- * @param   rcCurl              What curl returned.
- */
-static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pHttpInt, int rcCurl)
+ * @param   pThis           The HTTP/HTTPS client instance.
+ * @param   rcCurl          What curl returned.
+ */
+static int rtHttpGetCalcStatus(PRTHTTPINTERNAL pThis, int rcCurl)
 {
     int rc = VERR_INTERNAL_ERROR;
 
-    if (pHttpInt->pszRedirLocation)
-    {
-        RTStrFree(pHttpInt->pszRedirLocation);
-        pHttpInt->pszRedirLocation = NULL;
+    if (pThis->pszRedirLocation)
+    {
+        RTStrFree(pThis->pszRedirLocation);
+        pThis->pszRedirLocation = NULL;
     }
     if (rcCurl == CURLE_OK)
     {
-        curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_RESPONSE_CODE, &pHttpInt->lLastResp);
-        switch (pHttpInt->lLastResp)
+        curl_easy_getinfo(pThis->pCurl, CURLINFO_RESPONSE_CODE, &pThis->lLastResp);
+        switch (pThis->lLastResp)
         {
             case 200:
@@ -338,8 +508,8 @@
             {
                 const char *pszRedirect;
-                curl_easy_getinfo(pHttpInt->pCurl, CURLINFO_REDIRECT_URL, &pszRedirect);
+                curl_easy_getinfo(pThis->pCurl, CURLINFO_REDIRECT_URL, &pszRedirect);
                 size_t cb = strlen(pszRedirect);
                 if (cb > 0 && cb < 2048)
-                    pHttpInt->pszRedirLocation = RTStrDup(pszRedirect);
+                    pThis->pszRedirLocation = RTStrDup(pszRedirect);
                 rc = VERR_HTTP_REDIRECTED;
                 break;
@@ -399,9 +569,153 @@
 
 /**
+ * cURL callback for reporting progress, we use it for checking for abort.
+ */
+static int rtHttpProgress(void *pData, double rdTotalDownload, double rdDownloaded, double rdTotalUpload, double rdUploaded)
+{
+    PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pData;
+    AssertReturn(pThis->u32Magic == RTHTTP_MAGIC, 1);
+
+    pThis->cbDownloadHint = (uint64_t)rdTotalDownload;
+
+    return pThis->fAbort ? 1 : 0;
+}
+
+
+/**
+ * Whether we're likely to need SSL to handle the give URL.
+ *
+ * @returns true if we need, false if we probably don't.
+ * @param   pszUrl              The URL.
+ */
+static bool rtHttpNeedSsl(const char *pszUrl)
+{
+    return RTStrNICmp(pszUrl, RT_STR_TUPLE("https:")) == 0;
+}
+
+
+/**
+ * Applies recoded settings to the cURL instance before doing work.
+ *
+ * @returns IPRT status code.
+ * @param   pThis           The HTTP/HTTPS client instance.
+ * @param   pszUrl          The URL.
+ */
+static int rtHttpApplySettings(PRTHTTPINTERNAL pThis, const char *pszUrl)
+{
+    /*
+     * The URL.
+     */
+    int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_URL, pszUrl);
+    if (CURL_FAILURE(rcCurl))
+        return VERR_INVALID_PARAMETER;
+
+    /*
+     * Setup SSL.  Can be a bit of work.
+     */
+    rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1);
+    if (CURL_FAILURE(rcCurl))
+        return VERR_INVALID_PARAMETER;
+
+    const char *pszCaFile = pThis->pszCaFile;
+    if (   !pszCaFile
+        && rtHttpNeedSsl(pszUrl))
+    {
+        int rc = RTHttpUseTemporaryCaFile(pThis, NULL);
+        if (RT_SUCCESS(rc))
+            pszCaFile = pThis->pszCaFile;
+        else
+            return rc; /* Non-portable alternative: pszCaFile = "/etc/ssl/certs/ca-certificates.crt"; */
+    }
+    if (pszCaFile)
+    {
+        rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_CAINFO, pszCaFile);
+        if (CURL_FAILURE(rcCurl))
+            return VERR_INTERNAL_ERROR;
+    }
+
+    /*
+     * Progress/abort.
+     */
+    rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
+    if (CURL_FAILURE(rcCurl))
+        return VERR_INTERNAL_ERROR;
+    rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_PROGRESSDATA, (void *)pThis);
+    if (CURL_FAILURE(rcCurl))
+        return VERR_INTERNAL_ERROR;
+    rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_NOPROGRESS, (long)0);
+    if (CURL_FAILURE(rcCurl))
+        return VERR_INTERNAL_ERROR;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * cURL callback for writing data.
+ */
+static size_t rtHttpWriteData(void *pvBuf, size_t cbUnit, size_t cUnits, void *pvUser)
+{
+    PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser;
+
+    /*
+     * Do max size and overflow checks.
+     */
+    size_t const cbToAppend = cbUnit * cUnits;
+    size_t const cbCurSize  = pThis->Output.Mem.cb;
+    size_t const cbNewSize  = cbCurSize + cbToAppend;
+    if (   cbToAppend < RTHTTP_MAX_MEM_DOWNLOAD_SIZE
+        && cbNewSize  < RTHTTP_MAX_MEM_DOWNLOAD_SIZE)
+    {
+        if (cbNewSize + 1 <= pThis->Output.Mem.cbAllocated)
+        {
+            memcpy(&pThis->Output.Mem.pb[cbCurSize], pvBuf, cbToAppend);
+            pThis->Output.Mem.cb = cbNewSize;
+            pThis->Output.Mem.pb[cbNewSize] = '\0';
+            return VINF_SUCCESS;
+        }
+
+        /*
+         * We need to reallocate the output buffer.
+         */
+        /** @todo this could do with a better strategy wrt growth. */
+        size_t cbAlloc = RT_ALIGN_Z(cbNewSize + 1, 64);
+        if (   cbAlloc <= pThis->cbDownloadHint
+            && pThis->cbDownloadHint < RTHTTP_MAX_MEM_DOWNLOAD_SIZE)
+            cbAlloc = RT_ALIGN_Z(pThis->cbDownloadHint + 1, 64);
+
+        uint8_t *pbNew = (uint8_t *)RTMemRealloc(pThis->Output.Mem.pb, cbAlloc);
+        if (pbNew)
+        {
+            memcpy(&pbNew[cbCurSize], pvBuf, cbToAppend);
+            pbNew[cbNewSize] = '\0';
+
+            pThis->Output.Mem.cbAllocated = cbAlloc;
+            pThis->Output.Mem.pb = pbNew;
+            pThis->Output.Mem.cb = cbNewSize;
+            return VINF_SUCCESS;
+        }
+
+        pThis->rcOutput = VERR_NO_MEMORY;
+    }
+    else
+        pThis->rcOutput      = VERR_TOO_MUCH_DATA;
+
+    /*
+     * Failure - abort.
+     */
+    RTMemFree(pThis->Output.Mem.pb);
+    pThis->Output.Mem.pb = NULL;
+    pThis->Output.Mem.cb = RTHTTP_MAX_MEM_DOWNLOAD_SIZE;
+    pThis->fAbort        = true;
+    return 0;
+}
+
+
+/**
  * Internal worker that performs a HTTP GET.
  *
  * @returns IPRT status code.
- * @param   hHttp               The HTTP instance.
- * @param   pcszUrl             The URL.
+ * @param   hHttp               The HTTP/HTTPS client instance.
+ * @param   pszUrl              The URL.
  * @param   ppvResponse         Where to return the pointer to the allocated
  *                              response data (RTMemFree).  There will always be
@@ -409,77 +723,72 @@
  *                              is not part of the size returned via @a pcb.
  * @param   pcb                 The size of the response data.
- */
-RTR3DECL(int) rtHttpGet(RTHTTP hHttp, const char *pcszUrl, uint8_t **ppvResponse, size_t *pcb)
-{
-    PRTHTTPINTERNAL pHttpInt = hHttp;
-    RTHTTP_VALID_RETURN(pHttpInt);
-
-    pHttpInt->fAbort = false;
-
-    int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pcszUrl);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INVALID_PARAMETER;
-
-#if 0
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INVALID_PARAMETER;
-#endif
-
-    const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
-    if (pHttpInt->pcszCAFile)
-        pcszCAFile = pHttpInt->pcszCAFile;
-    if (RTFileExists(pcszCAFile))
-    {
-        rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
-        if (CURL_FAILED(rcCurl))
-            return VERR_INTERNAL_ERROR;
-    }
-
-    RTHTTPMEMCHUNK Chunk = { NULL, 0 };
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INTERNAL_ERROR;
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void *)&Chunk);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INTERNAL_ERROR;
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INTERNAL_ERROR;
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void *)pHttpInt);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INTERNAL_ERROR;
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INTERNAL_ERROR;
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_SSLVERSION, (long)CURL_SSLVERSION_TLSv1);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INVALID_PARAMETER;
-
-    rcCurl = curl_easy_perform(pHttpInt->pCurl);
-
-    int rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
+ *
+ * @remarks We ASSUME the API user doesn't do concurrent GETs in different
+ *          threads, because that will probably blow up!
+ */
+static int rtHttpGetToMem(RTHTTP hHttp, const char *pszUrl, uint8_t **ppvResponse, size_t *pcb)
+{
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN(pThis);
+
+    /*
+     * Reset the return values in case of more "GUI programming" on the client
+     * side (i.e. a programming style not bothering checking return codes).
+     */
+    *ppvResponse = NULL;
+    *pcb         = 0;
+
+    /*
+     * Set the busy flag (paranoia).
+     */
+    bool fBusy = ASMAtomicXchgBool(&pThis->fBusy, true);
+    AssertReturn(fBusy, VERR_WRONG_ORDER);
+
+    /*
+     * Reset the state and apply settings.
+     */
+    pThis->fAbort = false;
+    pThis->rcOutput = VINF_SUCCESS;
+    pThis->cbDownloadHint = 0;
+
+    int rc = rtHttpApplySettings(hHttp, pszUrl);
     if (RT_SUCCESS(rc))
     {
-        *ppvResponse = Chunk.pu8Mem;
-        *pcb         = Chunk.cb;
-    }
-    else
-    {
-        if (Chunk.pu8Mem)
-            RTMemFree(Chunk.pu8Mem);
-        *ppvResponse = NULL;
-        *pcb         = 0;
-    }
-
+        RT_ZERO(pThis->Output.Mem);
+        int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteData);
+        if (!CURL_FAILURE(rcCurl))
+            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEDATA, (void *)pThis);
+        if (!CURL_FAILURE(rcCurl))
+        {
+            /*
+             * Perform the HTTP operation.
+             */
+            rcCurl = curl_easy_perform(pThis->pCurl);
+            rc = rtHttpGetCalcStatus(pThis, rcCurl);
+            if (RT_SUCCESS(rc))
+                rc = pThis->rcOutput;
+            if (RT_SUCCESS(rc))
+            {
+                *ppvResponse = pThis->Output.Mem.pb;
+                *pcb         = pThis->Output.Mem.cb;
+            }
+            else if (pThis->Output.Mem.pb)
+                RTMemFree(pThis->Output.Mem.pb);
+            RT_ZERO(pThis->Output.Mem);
+        }
+        else
+            rc = VERR_INTERNAL_ERROR_3;
+    }
+
+    ASMAtomicWriteBool(&pThis->fBusy, false);
     return rc;
 }
 
 
-RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pcszUrl, char **ppszNotUtf8)
+RTR3DECL(int) RTHttpGetText(RTHTTP hHttp, const char *pszUrl, char **ppszNotUtf8)
 {
     uint8_t *pv;
     size_t   cb;
-    int rc = rtHttpGet(hHttp, pcszUrl, &pv, &cb);
+    int rc = rtHttpGetToMem(hHttp, pszUrl, &pv, &cb);
     if (RT_SUCCESS(rc))
     {
@@ -501,7 +810,7 @@
 
 
-RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pcszUrl, void **ppvResponse, size_t *pcb)
-{
-    return rtHttpGet(hHttp, pcszUrl, (uint8_t **)ppvResponse, pcb);
+RTR3DECL(int) RTHttpGetBinary(RTHTTP hHttp, const char *pszUrl, void **ppvResponse, size_t *pcb)
+{
+    return rtHttpGetToMem(hHttp, pszUrl, (uint8_t **)ppvResponse, pcb);
 }
 
@@ -513,13 +822,15 @@
 
 
-static size_t rtHttpWriteDataToFile(void *pvBuf, size_t cb, size_t n, void *pvUser)
-{
-    size_t cbAll = cb * n;
-    RTFILE hFile = (RTFILE)(intptr_t)pvUser;
-
+/**
+ * cURL callback for writing data to a file.
+ */
+static size_t rtHttpWriteDataToFile(void *pvBuf, size_t cbUnit, size_t cUnits, void *pvUser)
+{
+    PRTHTTPINTERNAL pThis = (PRTHTTPINTERNAL)pvUser;
     size_t cbWritten = 0;
-    int rc = RTFileWrite(hFile, pvBuf, cbAll, &cbWritten);
+    int rc = RTFileWrite(pThis->Output.hFile, pvBuf, cbUnit * cUnits, &cbWritten);
     if (RT_SUCCESS(rc))
         return cbWritten;
+    pThis->rcOutput = rc;
     return 0;
 }
@@ -528,69 +839,54 @@
 RTR3DECL(int) RTHttpGetFile(RTHTTP hHttp, const char *pszUrl, const char *pszDstFile)
 {
-    PRTHTTPINTERNAL pHttpInt = hHttp;
-    RTHTTP_VALID_RETURN(pHttpInt);
-
-    /*
-     * Set up the request.
-     */
-    pHttpInt->fAbort = false;
-
-    int rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_URL, pszUrl);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INVALID_PARAMETER;
-
-#if 0
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_VERBOSE, 1);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INVALID_PARAMETER;
-#endif
-
-    const char *pcszCAFile = "/etc/ssl/certs/ca-certificates.crt";
-    if (pHttpInt->pcszCAFile)
-        pcszCAFile = pHttpInt->pcszCAFile;
-    if (RTFileExists(pcszCAFile))
-    {
-        rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_CAINFO, pcszCAFile);
-        if (CURL_FAILED(rcCurl))
-            return VERR_INTERNAL_ERROR;
-    }
-
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteDataToFile);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INTERNAL_ERROR;
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSFUNCTION, &rtHttpProgress);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INTERNAL_ERROR;
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_PROGRESSDATA, (void *)pHttpInt);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INTERNAL_ERROR;
-    rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_NOPROGRESS, (long)0);
-    if (CURL_FAILED(rcCurl))
-        return VERR_INTERNAL_ERROR;
-
-    /*
-     * Open the output file.
-     */
-    RTFILE hFile;
-    int rc = RTFileOpen(&hFile, pszDstFile, RTFILE_O_WRITE | RTFILE_O_CREATE_REPLACE | RTFILE_O_DENY_READWRITE);
+    PRTHTTPINTERNAL pThis = hHttp;
+    RTHTTP_VALID_RETURN(pThis);
+
+    /*
+     * Set the busy flag (paranoia).
+     */
+    bool fBusy = ASMAtomicXchgBool(&pThis->fBusy, true);
+    AssertReturn(fBusy, VERR_WRONG_ORDER);
+
+    /*
+     * Reset the state and apply settings.
+     */
+    pThis->fAbort = false;
+    pThis->rcOutput = VINF_SUCCESS;
+    pThis->cbDownloadHint = 0;
+
+    int rc = rtHttpApplySettings(hHttp, pszUrl);
     if (RT_SUCCESS(rc))
     {
-        rcCurl = curl_easy_setopt(pHttpInt->pCurl, CURLOPT_WRITEDATA, (void *)(uintptr_t)hFile);
-        if (!CURL_FAILED(rcCurl))
+        pThis->Output.hFile = NIL_RTFILE;
+        int rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEFUNCTION, &rtHttpWriteDataToFile);
+        if (!CURL_FAILURE(rcCurl))
+            rcCurl = curl_easy_setopt(pThis->pCurl, CURLOPT_WRITEDATA, (void *)pThis);
+        if (!CURL_FAILURE(rcCurl))
         {
             /*
-             * Perform the request.
+             * Open the output file.
              */
-            rcCurl = curl_easy_perform(pHttpInt->pCurl);
-            rc = rtHttpGetCalcStatus(pHttpInt, rcCurl);
+            rc = RTFileOpen(&pThis->Output.hFile, pszDstFile, RTFILE_O_CREATE_REPLACE | RTFILE_O_WRITE | RTFILE_O_DENY_READWRITE);
+            if (RT_SUCCESS(rc))
+            {
+                /*
+                 * Perform the HTTP operation.
+                 */
+                rcCurl = curl_easy_perform(pThis->pCurl);
+                rc = rtHttpGetCalcStatus(pThis, rcCurl);
+                if (RT_SUCCESS(rc))
+                     rc = pThis->rcOutput;
+
+                int rc2 = RTFileClose(pThis->Output.hFile);
+                if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
+                    rc = rc2;
+            }
+            pThis->Output.hFile = NIL_RTFILE;
         }
         else
-            rc = VERR_INTERNAL_ERROR;
-
-        int rc2 = RTFileClose(hFile);
-        if (RT_FAILURE(rc2) && RT_SUCCESS(rc))
-            rc = rc2;
-    }
-
+            rc = VERR_INTERNAL_ERROR_3;
+    }
+
+    ASMAtomicWriteBool(&pThis->fBusy, false);
     return rc;
 }
Index: /trunk/src/VBox/Runtime/common/path/RTPathEnsureTrailingSeparator.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/path/RTPathEnsureTrailingSeparator.cpp	(revision 57612)
+++ /trunk/src/VBox/Runtime/common/path/RTPathEnsureTrailingSeparator.cpp	(revision 57613)
@@ -44,7 +44,12 @@
         if (RTPATH_IS_SLASH(ch) || RTPATH_IS_VOLSEP(ch))
             return off;
+        if (off + 2 <= cbPath)
+        {
+            pszPath[off++] = RTPATH_SLASH;
+            pszPath[off]   = '\0';
+            return off;
+        }
     }
-
-    if (off + 2 < cbPath)
+    else if (off + 3 <= cbPath)
     {
         pszPath[off++] = '.';
Index: /trunk/src/VBox/Runtime/common/path/RTPathGlob.cpp
===================================================================
--- /trunk/src/VBox/Runtime/common/path/RTPathGlob.cpp	(revision 57613)
+++ /trunk/src/VBox/Runtime/common/path/RTPathGlob.cpp	(revision 57613)
@@ -0,0 +1,2138 @@
+/* $Id$ */
+/** @file
+ * IPRT - RTPathGlob
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include "internal/iprt.h"
+#include <iprt/path.h>
+
+#include <iprt/asm.h>
+#include <iprt/assert.h>
+#include <iprt/buildconfig.h>
+#include <iprt/ctype.h>
+#include <iprt/dir.h>
+#include <iprt/env.h>
+#include <iprt/err.h>
+#include <iprt/mem.h>
+#include <iprt/string.h>
+#include <iprt/uni.h>
+
+#if defined(RT_OS_WINDOWS)
+# include <Windows.h>
+
+#elif defined(RT_OS_OS2)
+# define INCL_BASE
+# include <os2.h>
+
+#endif
+
+
+/*********************************************************************************************************************************
+*   Defined Constants And Macros                                                                                                 *
+*********************************************************************************************************************************/
+/** Maximum number of results. */
+#define RTPATHGLOB_MAX_RESULTS          _32K
+/** Maximum number of zero-or-more wildcards in a pattern.
+ * This limits stack usage and recursion depth, as well as execution time. */
+#define RTPATHMATCH_MAX_ZERO_OR_MORE    24
+/** Maximum number of variable items. */
+#define RTPATHMATCH_MAX_VAR_ITEMS       _4K
+
+
+
+/*********************************************************************************************************************************
+*   Structures and Typedefs                                                                                                      *
+*********************************************************************************************************************************/
+/**
+ * Matching operation.
+ */
+typedef enum RTPATHMATCHOP
+{
+    RTPATHMATCHOP_INVALID = 0,
+    /** EOS: Returns a match if at end of string. */
+    RTPATHMATCHOP_RETURN_MATCH_IF_AT_END,
+    /** Asterisk: Returns a match (trailing asterisk). */
+    RTPATHMATCHOP_RETURN_MATCH,
+    /** Asterisk: Returns a match (just asterisk), unless it's '.' or '..'. */
+    RTPATHMATCHOP_RETURN_MATCH_EXCEPT_DOT_AND_DOTDOT,
+    /** Plain text: Case sensitive string compare. */
+    RTPATHMATCHOP_STRCMP,
+    /** Plain text: Case insensitive string compare. */
+    RTPATHMATCHOP_STRICMP,
+    /** Question marks: Skips exactly one code point. */
+    RTPATHMATCHOP_SKIP_ONE_CODEPOINT,
+    /** Question marks: Skips exactly RTPATHMATCHCORE::cch code points. */
+    RTPATHMATCHOP_SKIP_MULTIPLE_CODEPOINTS,
+    /** Char set: Requires the next codepoint to be in the ASCII-7 set defined by
+     *            RTPATHMATCHCORE::pch & RTPATHMATCHCORE::cch.  No ranges. */
+    RTPATHMATCHOP_CODEPOINT_IN_SET_ASCII7,
+    /** Char set: Requires the next codepoint to not be in the ASCII-7 set defined
+     *            by RTPATHMATCHCORE::pch & RTPATHMATCHCORE::cch.  No ranges. */
+    RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_ASCII7,
+    /** Char set: Requires the next codepoint to be in the extended set defined by
+     *            RTPATHMATCHCORE::pch & RTPATHMATCHCORE::cch.  Ranges, UTF-8. */
+    RTPATHMATCHOP_CODEPOINT_IN_SET_EXTENDED,
+    /** Char set: Requires the next codepoint to not be in the extended set defined
+     *            by RTPATHMATCHCORE::pch & RTPATHMATCHCORE::cch.  Ranges, UTF-8. */
+    RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_EXTENDED,
+    /** Variable: Case sensitive variable value compare, RTPATHMATCHCORE::uOp2 is
+     *            the variable table index. */
+    RTPATHMATCHOP_VARIABLE_VALUE_CMP,
+    /** Variable: Case insensitive variable value compare, RTPATHMATCHCORE::uOp2 is
+     *            the variable table index. */
+    RTPATHMATCHOP_VARIABLE_VALUE_ICMP,
+    /** Asterisk: Match zero or more code points, there must be at least
+     * RTPATHMATCHCORE::cch code points after it. */
+    RTPATHMATCHOP_ZERO_OR_MORE,
+    /** Asterisk: Match zero or more code points, there must be at least
+     * RTPATHMATCHCORE::cch code points after it, unless it's '.' or '..'. */
+    RTPATHMATCHOP_ZERO_OR_MORE_EXCEPT_DOT_AND_DOTDOT,
+    /** End of valid operations.   */
+    RTPATHMATCHOP_END
+} RTPATHMATCHOP;
+
+/**
+ * Matching instruction.
+ */
+typedef struct RTPATHMATCHCORE
+{
+    /** The action to take. */
+    RTPATHMATCHOP       enmOpCode;
+    /** Generic value operand. */
+    uint16_t            uOp2;
+    /** Generic length operand. */
+    uint16_t            cch;
+    /** Generic string pointer operand. */
+    const char         *pch;
+} RTPATHMATCHCORE;
+/** Pointer to a matching instruction. */
+typedef RTPATHMATCHCORE *PRTPATHMATCHCORE;
+/** Pointer to a const matching instruction. */
+typedef RTPATHMATCHCORE const *PCRTPATHMATCHCORE;
+
+/**
+ * Path matching instruction allocator.
+ */
+typedef struct RTPATHMATCHALLOC
+{
+    /** Allocated array of instructions. */
+    PRTPATHMATCHCORE    paInstructions;
+    /** Index of the next free entry in paScratch. */
+    uint32_t            iNext;
+    /** Number of instructions allocated. */
+    uint32_t            cAllocated;
+} RTPATHMATCHALLOC;
+/** Pointer to a matching instruction allocator. */
+typedef RTPATHMATCHALLOC *PRTPATHMATCHALLOC;
+
+/**
+ * Path matching cache, mainly intended for variables like the PATH.
+ */
+typedef struct RTPATHMATCHCACHE
+{
+    /** @todo optimize later. */
+    uint32_t            iNothingYet;
+} RTPATHMATCHCACHE;
+/** Pointer to a path matching cache. */
+typedef RTPATHMATCHCACHE *PRTPATHMATCHCACHE;
+
+
+
+/** Parsed path entry.*/
+typedef struct RTPATHGLOBPPE
+{
+    /** Normal: Index into RTPATHGLOB::MatchInstrAlloc.paInstructions. */
+    uint32_t            iMatchProg : 16;
+    /** Set if this is a normal entry which is matched using iMatchProg. */
+    uint32_t            fNormal : 1;
+    /** !fNormal: Plain name that can be dealt with using without
+     * enumerating the whole directory, unless of course the file system is case
+     * sensitive and the globbing isn't (that needs figuring out on a per
+     * directory basis). */
+    uint32_t            fPlain : 1;
+    /** !fNormal: Match zero or more subdirectories. */
+    uint32_t            fStarStar : 1;
+    /** !fNormal: The whole component is a variable expansion. */
+    uint32_t            fExpVariable : 1;
+
+    /** Filter: Set if it only matches directories. */
+    uint32_t            fDir : 1;
+    /** Set if it's the final component. */
+    uint32_t            fFinal : 1;
+
+    /** Unused bits. */
+    uint32_t            fReserved : 2+8;
+} RTPATHGLOBPPE;
+
+
+typedef struct RTPATHGLOB
+{
+    /** Path buffer. */
+    char                szPath[RTPATH_MAX];
+    /** Temporary buffers. */
+    union
+    {
+        /** File system object info structure. */
+        RTFSOBJINFO     ObjInfo;
+        /** Directory entry buffer. */
+        RTDIRENTRY      DirEntry;
+        /** Padding the buffer to an unreasonably large size. */
+        uint8_t         abPadding[RTPATH_MAX + RT_OFFSETOF(RTDIRENTRY, szName)];
+    } u;
+
+
+    /** Where to insert the next one.*/
+    PRTPATHGLOBENTRY   *ppNext;
+    /** The head pointer. */
+    PRTPATHGLOBENTRY    pHead;
+    /** Result count. */
+    uint32_t            cResults;
+    /** Counts path overflows. */
+    uint32_t            cPathOverflows;
+    /** The input flags. */
+    uint32_t            fFlags;
+    /** Matching instruction allocator. */
+    RTPATHMATCHALLOC    MatchInstrAlloc;
+    /** Matching state. */
+    RTPATHMATCHCACHE    MatchCache;
+
+    /** The pattern string.   */
+    const char         *pszPattern;
+    /** The parsed path.   */
+    PRTPATHPARSED       pParsed;
+    /** The component to start with. */
+    uint16_t            iFirstComp;
+    /** The corresponding path offset (previous components already present). */
+    uint16_t            offFirstPath;
+    /** Path component information we need. */
+    RTPATHGLOBPPE       aComps[1];
+} RTPATHGLOB;
+typedef RTPATHGLOB *PRTPATHGLOB;
+
+
+/*********************************************************************************************************************************
+*   Internal Functions                                                                                                           *
+*********************************************************************************************************************************/
+static int rtPathGlobExecRecursiveStarStar(PRTPATHGLOB pGlob, size_t offPath, uint32_t iStarStarComp, size_t offStarStarPath);
+static int rtPathGlobExecRecursiveVarExp(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp);
+static int rtPathGlobExecRecursivePlainText(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp);
+static int rtPathGlobExecRecursiveGeneric(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp);
+
+
+/**
+ * Implements the two variable access functions for a simple one value variable.
+ */
+#define RTPATHMATCHVAR_SIMPLE(a_Name, a_GetStrExpr) \
+    static DECLCALLBACK(int) RT_CONCAT(rtPathVarQuery_,a_Name)(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue, \
+                                                               PRTPATHMATCHCACHE pCache) \
+    { \
+        if (iItem == 0) \
+        { \
+            const char *pszValue = a_GetStrExpr; \
+            size_t      cchValue = strlen(pszValue); \
+            if (cchValue + 1 <= cbBuf) \
+            { \
+                memcpy(pszBuf, pszValue, cchValue + 1); \
+                *pcchValue = cchValue; \
+                return VINF_EOF; \
+            } \
+            return VERR_BUFFER_OVERFLOW; \
+        } \
+        NOREF(pCache);\
+        return VERR_EOF; \
+    } \
+    static DECLCALLBACK(int) RT_CONCAT(rtPathVarMatch_,a_Name)(const char *pchMatch, size_t cchMatch, bool fIgnoreCase, \
+                                                               size_t *pcchMatched) \
+    { \
+        const char *pszValue = a_GetStrExpr; \
+        size_t      cchValue = strlen(pszValue); \
+        if (   cchValue >= cchMatch \
+            && (  !fIgnoreCase \
+                ? memcmp(pszValue, pchMatch, cchValue) == 0 \
+                : RTStrNICmp(pszValue, pchMatch, cchValue) == 0) ) \
+        { \
+            *pcchMatched = cchValue; \
+            return VINF_SUCCESS; \
+        } \
+        return VERR_MISMATCH; \
+    } \
+    typedef int RT_CONCAT(DummyColonType_,a_Name)
+
+/**
+ * Implements mapping a glob variable to an environment variable.
+ */
+#define RTPATHMATCHVAR_SIMPLE_ENVVAR(a_Name, a_pszEnvVar, a_cbMaxValue) \
+    static DECLCALLBACK(int) RT_CONCAT(rtPathVarQuery_,a_Name)(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue, \
+                                                               PRTPATHMATCHCACHE pCache) \
+    { \
+        if (iItem == 0) \
+        { \
+            int rc = RTEnvGetEx(RTENV_DEFAULT, a_pszEnvVar, pszBuf, cbBuf, pcchValue); \
+            if (RT_SUCCESS(rc)) \
+                return VINF_EOF; \
+            if (rc != VERR_ENV_VAR_NOT_FOUND) \
+                return rc; \
+        } \
+        NOREF(pCache);\
+        return VERR_EOF; \
+    } \
+    static DECLCALLBACK(int) RT_CONCAT(rtPathVarMatch_,a_Name)(const char *pchMatch, size_t cchMatch, bool fIgnoreCase, \
+                                                               size_t *pcchMatched) \
+    { \
+        char   szValue[a_cbMaxValue]; \
+        size_t cchValue; \
+        int rc = RTEnvGetEx(RTENV_DEFAULT, a_pszEnvVar, szValue, sizeof(szValue), &cchValue); \
+        if (   RT_SUCCESS(rc) \
+            && cchValue >= cchMatch \
+            && (  !fIgnoreCase \
+                ? memcmp(szValue, pchMatch, cchValue) == 0 \
+                : RTStrNICmp(szValue, pchMatch, cchValue) == 0) ) \
+        { \
+            *pcchMatched = cchValue; \
+            return VINF_SUCCESS; \
+        } \
+        return VERR_MISMATCH; \
+    } \
+    typedef int RT_CONCAT(DummyColonType_,a_Name)
+
+/**
+ * Implements mapping a glob variable to multiple environment variable values.
+ * @param   a_apszVarNames      Assumes to be a global variable that RT_ELEMENTS
+ *                              works correctly on.
+ */
+#define RTPATHMATCHVAR_MULTIPLE_ENVVARS(a_Name, a_apszVarNames, a_cbMaxValue) \
+    static DECLCALLBACK(int) RT_CONCAT(rtPathVarQuery_,a_Name)(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue, \
+                                                               PRTPATHMATCHCACHE pCache) \
+    { \
+        if (iItem < RT_ELEMENTS(a_apszVarNames)) \
+        { \
+            int rc = RTEnvGetEx(RTENV_DEFAULT, a_apszVarNames[iItem], pszBuf, cbBuf, pcchValue); \
+            if (RT_SUCCESS(rc)) \
+                return iItem + 1 == RT_ELEMENTS(a_apszVarNames) ? VINF_EOF : VINF_SUCCESS; \
+            if (rc == VERR_ENV_VAR_NOT_FOUND) \
+                rc = VERR_TRY_AGAIN; \
+            return rc; \
+        } \
+        NOREF(pCache);\
+        return VERR_EOF; \
+    } \
+    static DECLCALLBACK(int) RT_CONCAT(rtPathVarMatch_,a_Name)(const char *pchMatch, size_t cchMatch, bool fIgnoreCase, \
+                                                               size_t *pcchMatched) \
+    { \
+        for (uint32_t iItem = 0; iItem < RT_ELEMENTS(a_apszVarNames); iItem++) \
+        { \
+            char   szValue[a_cbMaxValue]; \
+            size_t cchValue; \
+            int rc = RTEnvGetEx(RTENV_DEFAULT, a_apszVarNames[iItem], szValue, sizeof(szValue), &cchValue);\
+            if (   RT_SUCCESS(rc) \
+                && cchValue >= cchMatch \
+                && (  !fIgnoreCase \
+                    ? memcmp(szValue, pchMatch, cchValue) == 0 \
+                    : RTStrNICmp(szValue, pchMatch, cchValue) == 0) ) \
+            { \
+                *pcchMatched = cchValue; \
+                return VINF_SUCCESS; \
+            } \
+        } \
+        return VERR_MISMATCH; \
+    } \
+    typedef int RT_CONCAT(DummyColonType_,a_Name)
+
+
+RTPATHMATCHVAR_SIMPLE(Arch, RTBldCfgTargetArch());
+RTPATHMATCHVAR_SIMPLE(Bits, RT_XSTR(ARCH_BITS));
+#ifdef RT_OS_WINDOWS
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinAppData,                    "AppData",              RTPATH_MAX);
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinProgramData,                "ProgramData",          RTPATH_MAX);
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinProgramFiles,               "ProgramFiles",         RTPATH_MAX);
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinCommonProgramFiles,         "CommonProgramFiles",       RTPATH_MAX);
+# if defined(RT_ARCH_AMD64) || defined(RT_ARCH_X86)
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinOtherProgramFiles,          "ProgramFiles(x86)",        RTPATH_MAX);
+RTPATHMATCHVAR_SIMPLE_ENVVAR(WinOtherCommonProgramFiles,    "CommonProgramFiles(x86)",  RTPATH_MAX);
+# else
+#  error "Port ME!"
+# endif
+static const char * const a_apszWinProgramFilesVars[] =
+{
+    "ProgramFiles",
+# ifdef RT_ARCH_AMD64
+    "ProgramFiles(x86)",
+# endif
+};
+RTPATHMATCHVAR_MULTIPLE_ENVVARS(WinAllProgramFiles, a_apszWinProgramFilesVars, RTPATH_MAX);
+static const char * const a_apszWinCommonProgramFilesVars[] =
+{
+    "CommonProgramFiles",
+# ifdef RT_ARCH_AMD64
+    "CommonProgramFiles(x86)",
+# endif
+};
+RTPATHMATCHVAR_MULTIPLE_ENVVARS(WinAllCommonProgramFiles, a_apszWinCommonProgramFilesVars, RTPATH_MAX);
+#endif
+
+
+/**
+ * @interface_method_impl{RTPATHMATCHVAR::pfnQuery, Enumerates the PATH}.
+ */
+static DECLCALLBACK(int) rtPathVarQuery_Path(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue,
+                                             PRTPATHMATCHCACHE pCache)
+{
+    /*
+     * Query the PATH value.
+     */
+/** @todo cache this in pCache with iItem and offset.   */
+    char       *pszPathFree = NULL;
+    char       *pszPath     = pszBuf;
+    size_t      cchActual;
+    const char *pszVarNm    = "PATH";
+    int rc = RTEnvGetEx(RTENV_DEFAULT, pszVarNm, pszPath, cbBuf, &cchActual);
+#ifdef RT_OS_WINDOWS
+    if (rc == VERR_ENV_VAR_NOT_FOUND)
+        rc = RTEnvGetEx(RTENV_DEFAULT, pszVarNm = "Path", pszPath, cbBuf, &cchActual);
+#endif
+    if (rc == VERR_BUFFER_OVERFLOW)
+    {
+        for (uint32_t iTry = 0; iTry < 10; iTry++)
+        {
+            size_t cbPathBuf = RT_ALIGN_Z(cchActual + 1 + 64 * iTry, 64);
+            pszPathFree = (char *)RTMemTmpAlloc(cbPathBuf);
+            rc = RTEnvGetEx(RTENV_DEFAULT, pszVarNm, pszPathFree, cbPathBuf, &cchActual);
+            if (RT_SUCCESS(rc))
+                break;
+            RTMemTmpFree(pszPathFree);
+            AssertReturn(cchActual >= cbPathBuf, VERR_INTERNAL_ERROR_3);
+        }
+        pszPath = pszPathFree;
+    }
+
+    /*
+     * Spool forward to the given PATH item.
+     */
+    rc = VERR_EOF;
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+    const char  chSep = ';';
+#else
+    const char  chSep = ':';
+#endif
+    while (*pszPath != '\0')
+    {
+        char *pchSep = strchr(pszPath, chSep);
+        if (iItem > 0)
+        {
+            /* If we didn't find a separator, the item doesn't exists. Quit. */
+            if (!pchSep)
+                break;
+
+            /* We ignore empty strings, which is probably not entirely correct,
+               but works better on DOS based system with many entries added
+               without checking whether there is a trailing separator or not.
+               Thus, the current directory is only searched if a '.' is present
+               in the PATH. */
+            if (pchSep != pszPath)
+            {
+                pszPath = pchSep;
+                iItem--;
+            }
+            pszPath++;
+        }
+        else
+        {
+            /* We've reached the item we wanted. */
+            size_t cchComp = pchSep ? pszPath - pchSep : strlen(pszPath);
+            if (cchComp < cbBuf)
+            {
+                if (pszBuf != pszPath)
+                    memmove(pszBuf, pszPath, cchComp);
+                pszBuf[cchComp] = '\0';
+                rc = pchSep ? VINF_SUCCESS : VINF_EOF;
+            }
+            else
+                rc = VERR_BUFFER_OVERFLOW;
+            break;
+        }
+    }
+
+    if (pszPathFree)
+        RTMemTmpFree(pszPathFree);
+    return rc;
+}
+
+
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+/**
+ * @interface_method_impl{RTPATHMATCHVAR::pfnQuery,
+ *      The system drive letter + colon.}.
+ */
+static DECLCALLBACK(int) rtPathVarQuery_DosSystemDrive(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue,
+                                                       PRTPATHMATCHCACHE pCache)
+{
+    if (iItem == 0)
+    {
+        AssertReturn(cbBuf >= 3, VERR_BUFFER_OVERFLOW);
+
+# ifdef RT_OS_WINDOWS
+        /* Since this is used at the start of a pattern, we assume
+           we've got more than enough buffer space. */
+        PRTUTF16 pwszTmp = (PRTUTF16)pszBuf;
+        UINT cch = GetSystemWindowsDirectoryW(pwszTmp, (UINT)(cbBuf / sizeof(WCHAR)));
+        if (cch >= 2)
+        {
+            RTUTF16 wcDrive = pwszTmp[0];
+            if (   RT_C_IS_ALPHA(wcDrive)
+                && pwszTmp[1] == ':')
+            {
+                pszBuf[0] = wcDrive;
+                pszBuf[1] = ':';
+                pszBuf[2] = '\0';
+                return VINF_EOF;
+            }
+        }
+# else
+        ULONG ulDrive = ~(ULONG)0;
+        APIRET rc = DosQuerySysInfo(QSV_BOOT_DRIVE, QSV_BOOT_DRIVE, &ulDrive, sizeof(ulDrive));
+        ulDrive--; /* 1 = 'A' */
+        if (   rc == NO_ERROR
+            && ulDrive <= (ULONG)'Z')
+        {
+            pszBuf[0] = (char)ulDrive + 'A';
+            pszBuf[1] = ':';
+            pszBuf[2] = '\0';
+            return VINF_EOF;
+        }
+# endif
+        return VERR_INTERNAL_ERROR_4;
+    }
+    return VERR_EOF;
+}
+#endif
+
+
+#ifdef RT_OS_WINDOWS
+/**
+ * @interface_method_impl{RTPATHMATCHVAR::pfnQuery,
+ *      The system root directory (C:\Windows).}.
+ */
+static DECLCALLBACK(int) rtPathVarQuery_WinSystemRoot(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue,
+                                                      PRTPATHMATCHCACHE pCache)
+{
+    if (iItem == 0)
+    {
+        Assert(pszBuf); Assert(cbBuf);
+        RTUTF16 wszSystemRoot[MAX_PATH];
+        UINT cchSystemRoot = GetSystemWindowsDirectoryW(wszSystemRoot, MAX_PATH);
+        if (cchSystemRoot > 0)
+            return RTUtf16ToUtf8Ex(wszSystemRoot, cchSystemRoot, &pszBuf, cbBuf, NULL);
+        return RTErrConvertFromWin32(GetLastError());
+    }
+    return VERR_EOF;
+}
+#endif
+
+#undef RTPATHMATCHVAR_SIMPLE
+#undef RTPATHMATCHVAR_SIMPLE_ENVVAR
+#undef RTPATHMATCHVAR_DOUBLE_ENVVAR
+
+/**
+ * Matching variable lookup table.
+ * Currently so small we don't bother sorting it and doing binary lookups.
+ */
+static struct RTPATHMATCHVAR
+{
+    /** The variable name. */
+    const char     *pszName;
+    /** The variable name length. */
+    uint16_t        cchName;
+    /** Only available as the verify first component.  */
+    bool            fFirstOnly;
+
+    /**
+     * Queries a given variable value.
+     *
+     * @returns IPRT status code.
+     * @retval  VERR_BUFFER_OVERFLOW
+     * @retval  VERR_TRY_AGAIN if the caller should skip this value item and try the
+     *          next one instead (e.g. env var not present).
+     * @retval  VINF_EOF when retrieving the last one, if possible.
+     * @retval  VERR_EOF when @a iItem is past the item space.
+     *
+     * @param   iItem       The variable value item to retrieve. (A variable may
+     *                      have more than one value, e.g. 'BothProgramFile' on a
+     *                      64-bit system or 'Path'.)
+     * @param   pszBuf      Where to return the value.
+     * @param   cbBuf       The buffer size.
+     * @param   pcchValue   Where to return the length of the return string.
+     * @param   pCache      Pointer to the path matching cache.  May speed up
+     *                      enumerating PATH items and similar.
+     */
+    DECLCALLBACKMEMBER(int, pfnQuery)(uint32_t iItem, char *pszBuf, size_t cbBuf, size_t *pcchValue, PRTPATHMATCHCACHE pCache);
+
+    /**
+     * Matching method, optional.
+     *
+     * @returns IPRT status code.
+     * @retval  VINF_SUCCESS on match.
+     * @retval  VERR_MISMATCH on mismatch.
+     *
+     * @param   pszMatch    String to match with (not terminated).
+     * @param   cchMatch    The length of what we match with.
+     * @param   fIgnoreCase Whether to ignore case or not when comparing.
+     * @param   pcchMatched Where to return the length of the match (value length).
+     */
+    DECLCALLBACKMEMBER(int, pfnMatch)(const char *pchMatch, size_t cchMatch, bool fIgnoreCase, size_t *pcchMatched);
+
+} const g_aVariables[] =
+{
+    { RT_STR_TUPLE("Arch"),                     false,  rtPathVarQuery_Arch, rtPathVarMatch_Arch },
+    { RT_STR_TUPLE("Bits"),                     false,  rtPathVarQuery_Bits, rtPathVarMatch_Bits },
+    { RT_STR_TUPLE("Path"),                     true,   rtPathVarQuery_Path, NULL },
+#if defined(RT_OS_WINDOWS) || defined(RT_OS_OS2)
+    { RT_STR_TUPLE("SystemDrive"),              true,   rtPathVarQuery_DosSystemDrive, NULL },
+#endif
+#ifdef RT_OS_WINDOWS
+    { RT_STR_TUPLE("SystemRoot"),               true,   rtPathVarQuery_WinSystemRoot, NULL },
+    { RT_STR_TUPLE("AppData"),                  true,   rtPathVarQuery_WinAppData, NULL },
+    { RT_STR_TUPLE("ProgramData"),              true,   rtPathVarQuery_WinProgramData, NULL },
+    { RT_STR_TUPLE("ProgramFiles"),             true,   rtPathVarQuery_WinProgramFiles, NULL },
+    { RT_STR_TUPLE("OtherProgramFiles"),        true,   rtPathVarQuery_WinOtherProgramFiles, NULL },
+    { RT_STR_TUPLE("AllProgramFiles"),          true,   rtPathVarQuery_WinAllProgramFiles, NULL },
+    { RT_STR_TUPLE("CommonProgramFiles"),       true,   rtPathVarQuery_WinCommonProgramFiles, NULL },
+    { RT_STR_TUPLE("OtherCommonProgramFiles"),  true,   rtPathVarQuery_WinOtherCommonProgramFiles, NULL },
+    { RT_STR_TUPLE("AllCommonProgramFiles"),    true,   rtPathVarQuery_WinAllCommonProgramFiles, NULL },
+#endif
+};
+
+
+
+/**
+ * Handles a complicated set.
+ *
+ * A complicated set is either using ranges, character classes or code points
+ * outside the ASCII-7 range.
+ *
+ * @returns VINF_SUCCESS or VERR_MISMATCH.  May also return UTF-8 decoding
+ *          errors as well as VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED.
+ *
+ * @param   ucInput     The input code point to match with.
+ * @param   pchSet      The start of the set specification (after caret).
+ * @param   cchSet      The length of the set specification.
+ */
+static int rtPathMatchExecExtendedSet(RTUNICP ucInput, const char *pchSet, size_t cchSet)
+{
+    while (cchSet > 0)
+    {
+        RTUNICP ucSet;
+        int rc = RTStrGetCpNEx(&pchSet, &cchSet, &ucSet);
+        AssertRCReturn(rc, rc);
+
+        /*
+         * Check for character class, collating symbol and equvalence class.
+         */
+        if (ucSet == '[' && cchSet > 0)
+        {
+            char chNext = *pchSet;
+            if (chNext == ':')
+            {
+#define CHECK_CHAR_CLASS(a_szClassNm, a_BoolTestExpr) \
+                    if (   cchSet >= sizeof(a_szClassNm) \
+                        && memcmp(pchSet, a_szClassNm "]", sizeof(a_szClassNm)) == 0) \
+                    { \
+                        if (a_BoolTestExpr) \
+                            return VINF_SUCCESS; \
+                        pchSet += sizeof(a_szClassNm); \
+                        cchSet -= sizeof(a_szClassNm); \
+                        continue; \
+                    } do { } while (0)
+
+                CHECK_CHAR_CLASS(":alpha:", RTUniCpIsAlphabetic(ucInput));
+                CHECK_CHAR_CLASS(":alnum:", RTUniCpIsAlphabetic(ucInput) || RTUniCpIsDecDigit(ucInput)); /** @todo figure what's correct here and fix uni.h */
+                CHECK_CHAR_CLASS(":blank:", ucInput == ' ' || ucInput == '\t');
+                CHECK_CHAR_CLASS(":cntrl:", ucInput < 31 || ucInput == 127);
+                CHECK_CHAR_CLASS(":digit:", RTUniCpIsDecDigit(ucInput));
+                CHECK_CHAR_CLASS(":lower:", RTUniCpIsLower(ucInput));
+                CHECK_CHAR_CLASS(":print:", RTUniCpIsAlphabetic(ucInput) || (RT_C_IS_PRINT(ucInput) && ucInput < 127)); /** @todo fixme*/
+                CHECK_CHAR_CLASS(":punct:", RT_C_IS_PRINT(ucInput) && ucInput < 127); /** @todo fixme*/
+                CHECK_CHAR_CLASS(":space:", RTUniCpIsSpace(ucInput));
+                CHECK_CHAR_CLASS(":upper:", RTUniCpIsUpper(ucInput));
+                CHECK_CHAR_CLASS(":xdigit:", RTUniCpIsHexDigit(ucInput));
+                AssertMsgFailedReturn(("Unknown or malformed char class: '%.*s'\n", cchSet + 1, pchSet - 1),
+                                      VERR_PATH_GLOB_UNKNOWN_CHAR_CLASS);
+#undef CHECK_CHAR_CLASS
+            }
+            /** @todo implement collating symbol and equvalence class. */
+            else if (chNext == '=' || chNext == '.')
+                AssertFailedReturn(VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED);
+        }
+
+        /*
+         * Check for range (leading or final dash does not constitute a range).
+         */
+        if (cchSet > 1 && *pchSet == '-')
+        {
+            pchSet++;                   /* skip dash */
+            cchSet--;
+
+            RTUNICP ucSet2;
+            rc = RTStrGetCpNEx(&pchSet, &cchSet, &ucSet2);
+            AssertRCReturn(rc, rc);
+            Assert(ucSet < ucSet2);
+            if (ucInput >= ucSet && ucInput <= ucSet2)
+                return VINF_SUCCESS;
+        }
+        /*
+         * Single char comparison.
+         */
+        else if (ucInput == ucSet)
+            return VINF_SUCCESS;
+    }
+    return VERR_MISMATCH;
+}
+
+
+/**
+ * Variable matching fallback using the query function.
+ *
+ * This must not be inlined as it consuming a lot of stack!  Which is why it's
+ * placed a couple of functions away from the recursive rtPathExecMatch.
+ *
+ * @returns VINF_SUCCESS or VERR_MISMATCH.
+ * @param   pchInput            The current input position.
+ * @param   cchInput            The amount of input left..
+ * @param   idxVar              The variable table index.
+ * @param   fIgnoreCase         Whether to ignore case when comparing.
+ * @param   pcchMatched         Where to return how much we actually matched up.
+ * @param   pCache              Pointer to the path matching cache.
+ */
+DECL_NO_INLINE(static, int) rtPathMatchExecVariableFallback(const char *pchInput, size_t cchInput, uint16_t idxVar,
+                                                            bool fIgnoreCase, size_t *pcchMatched, PRTPATHMATCHCACHE pCache)
+{
+    for (uint32_t iItem = 0; iItem < RTPATHMATCH_MAX_VAR_ITEMS; iItem++)
+    {
+        char   szValue[RTPATH_MAX];
+        size_t cchValue;
+        int rc = g_aVariables[idxVar].pfnQuery(iItem, szValue, sizeof(szValue), &cchValue, pCache);
+        if (RT_SUCCESS(rc))
+        {
+            if (cchValue <= cchInput)
+            {
+                if (  !fIgnoreCase
+                    ? memcmp(pchInput, szValue, cchValue) == 0
+                    : RTStrNICmp(pchInput, szValue, cchValue) == 0)
+                {
+                    *pcchMatched = cchValue;
+                    return VINF_SUCCESS;
+                }
+            }
+            if (rc == VINF_EOF)
+                return VERR_MISMATCH;
+        }
+        else if (rc == VERR_EOF)
+            return VERR_MISMATCH;
+        else
+            Assert(rc == VERR_BUFFER_OVERFLOW || rc == VERR_TRY_AGAIN);
+    }
+    AssertFailed();
+    return VERR_MISMATCH;
+}
+
+
+/**
+ * Variable matching worker.
+ *
+ * @returns VINF_SUCCESS or VERR_MISMATCH.
+ * @param   pchInput            The current input position.
+ * @param   cchInput            The amount of input left..
+ * @param   idxVar              The variable table index.
+ * @param   fIgnoreCase         Whether to ignore case when comparing.
+ * @param   pcchMatched         Where to return how much we actually matched up.
+ * @param   pCache              Pointer to the path matching cache.
+ */
+static int rtPathMatchExecVariable(const char *pchInput, size_t cchInput, uint16_t idxVar,
+                                   bool fIgnoreCase, size_t *pcchMatched, PRTPATHMATCHCACHE pCache)
+{
+    Assert(idxVar < RT_ELEMENTS(g_aVariables));
+    if (g_aVariables[idxVar].pfnMatch)
+        return g_aVariables[idxVar].pfnMatch(pchInput, cchInput, fIgnoreCase, pcchMatched);
+    return rtPathMatchExecVariableFallback(pchInput, cchInput, idxVar, fIgnoreCase, pcchMatched, pCache);
+}
+
+
+/**
+ * Variable matching worker.
+ *
+ * @returns VINF_SUCCESS or VERR_MISMATCH.
+ * @param   pchInput            The current input position.
+ * @param   cchInput            The amount of input left..
+ * @param   pProg               The first matching program instruction.
+ * @param   pCache              Pointer to the path matching cache.
+ */
+static int rtPathMatchExec(const char *pchInput, size_t cchInput, PCRTPATHMATCHCORE pProg, PRTPATHMATCHCACHE pCache)
+{
+    for (;;)
+    {
+        switch (pProg->enmOpCode)
+        {
+            case RTPATHMATCHOP_RETURN_MATCH_IF_AT_END:
+                return cchInput == 0 ? VINF_SUCCESS : VERR_MISMATCH;
+
+            case RTPATHMATCHOP_RETURN_MATCH:
+                return VINF_SUCCESS;
+
+            case RTPATHMATCHOP_RETURN_MATCH_EXCEPT_DOT_AND_DOTDOT:
+                if (   cchInput > 2
+                    || cchInput < 1
+                    || pchInput[0] != '.'
+                    || (cchInput == 2 && pchInput[1] != '.') )
+                    return VINF_SUCCESS;
+                return VERR_MISMATCH;
+
+            case RTPATHMATCHOP_STRCMP:
+                if (pProg->cch > cchInput)
+                    return VERR_MISMATCH;
+                if (memcmp(pchInput, pProg->pch, pProg->cch) != 0)
+                    return VERR_MISMATCH;
+                cchInput -= pProg->cch;
+                pchInput += pProg->cch;
+                break;
+
+            case RTPATHMATCHOP_STRICMP:
+                if (pProg->cch > cchInput)
+                    return VERR_MISMATCH;
+                if (RTStrNICmp(pchInput, pProg->pch, pProg->cch) != 0)
+                    return VERR_MISMATCH;
+                cchInput -= pProg->cch;
+                pchInput += pProg->cch;
+                break;
+
+            case RTPATHMATCHOP_SKIP_ONE_CODEPOINT:
+            {
+                if (cchInput == 0)
+                    return VERR_MISMATCH;
+                RTUNICP ucInputIgnore;
+                int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInputIgnore);
+                AssertRCReturn(rc, rc);
+                break;
+            }
+
+            case RTPATHMATCHOP_SKIP_MULTIPLE_CODEPOINTS:
+            {
+                uint16_t cCpsLeft = pProg->cch;
+                Assert(cCpsLeft > 1);
+                if (cCpsLeft > cchInput)
+                    return VERR_MISMATCH;
+                while (cCpsLeft-- > 0)
+                {
+                    RTUNICP ucInputIgnore;
+                    int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInputIgnore);
+                    if (RT_FAILURE(rc))
+                        return rc == VERR_END_OF_STRING ? VERR_MISMATCH : rc;
+                }
+                break;
+            }
+
+            case RTPATHMATCHOP_CODEPOINT_IN_SET_ASCII7:
+            {
+                if (cchInput == 0)
+                    return VERR_MISMATCH;
+                RTUNICP ucInput;
+                int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInput);
+                AssertRCReturn(rc, rc);
+                if (ucInput >= 0x80)
+                    return VERR_MISMATCH;
+                if (memchr(pProg->pch, (char)ucInput, pProg->cch) == NULL)
+                    return VERR_MISMATCH;
+                break;
+            }
+
+            case RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_ASCII7:
+            {
+                if (cchInput == 0)
+                    return VERR_MISMATCH;
+                RTUNICP ucInput;
+                int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInput);
+                AssertRCReturn(rc, rc);
+                if (ucInput >= 0x80)
+                    break;
+                if (memchr(pProg->pch, (char)ucInput, pProg->cch) != NULL)
+                    return VERR_MISMATCH;
+                break;
+            }
+
+            case RTPATHMATCHOP_CODEPOINT_IN_SET_EXTENDED:
+            {
+                if (cchInput == 0)
+                    return VERR_MISMATCH;
+                RTUNICP ucInput;
+                int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInput);
+                AssertRCReturn(rc, rc);
+                rc = rtPathMatchExecExtendedSet(ucInput, pProg->pch, pProg->cch);
+                if (rc == VINF_SUCCESS)
+                    break;
+                return rc;
+            }
+
+            case RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_EXTENDED:
+            {
+                if (cchInput == 0)
+                    return VERR_MISMATCH;
+                RTUNICP ucInput;
+                int rc = RTStrGetCpNEx(&pchInput, &cchInput, &ucInput);
+                AssertRCReturn(rc, rc);
+                rc = rtPathMatchExecExtendedSet(ucInput, pProg->pch, pProg->cch);
+                if (rc == VERR_MISMATCH)
+                    break;
+                if (rc == VINF_SUCCESS)
+                    rc = VERR_MISMATCH;
+                return rc;
+            }
+
+            case RTPATHMATCHOP_VARIABLE_VALUE_CMP:
+            case RTPATHMATCHOP_VARIABLE_VALUE_ICMP:
+            {
+                size_t cchMatched = 0;
+                int rc = rtPathMatchExecVariable(pchInput, cchInput, pProg->uOp2,
+                                                 pProg->enmOpCode == RTPATHMATCHOP_VARIABLE_VALUE_ICMP, &cchMatched, pCache);
+                if (rc == VINF_SUCCESS)
+                {
+                    pchInput += cchMatched;
+                    cchInput -= cchMatched;
+                    break;
+                }
+                return rc;
+            }
+
+            /*
+             * This is the expensive one. It always completes the program.
+             */
+            case RTPATHMATCHOP_ZERO_OR_MORE:
+            {
+                if (cchInput < pProg->cch)
+                    return VERR_MISMATCH;
+                size_t cchMatched = cchInput - pProg->cch;
+                do
+                {
+                    int rc = rtPathMatchExec(&pchInput[cchMatched], cchInput - cchMatched, pProg + 1, pCache);
+                    if (RT_SUCCESS(rc))
+                        return rc;
+                } while (cchMatched-- > 0);
+                return VERR_MISMATCH;
+            }
+
+            /*
+             * Variant of the above that doesn't match '.' and '..' entries.
+             */
+            case RTPATHMATCHOP_ZERO_OR_MORE_EXCEPT_DOT_AND_DOTDOT:
+            {
+                if (cchInput < pProg->cch)
+                    return VERR_MISMATCH;
+                if (   cchInput <= 2
+                    && cchInput > 0
+                    && pchInput[0] == '.'
+                    && (cchInput == 1 || pchInput[1] == '.') )
+                    return VERR_MISMATCH;
+                size_t cchMatched = cchInput - pProg->cch;
+                do
+                {
+                    int rc = rtPathMatchExec(&pchInput[cchMatched], cchInput - cchMatched, pProg + 1, pCache);
+                    if (RT_SUCCESS(rc))
+                        return rc;
+                } while (cchMatched-- > 0);
+                return VERR_MISMATCH;
+            }
+
+            default:
+                AssertMsgFailedReturn(("enmOpCode=%d\n", pProg->enmOpCode), VERR_INTERNAL_ERROR_3);
+        }
+
+        pProg++;
+    }
+}
+
+
+
+
+/**
+ * Compiles a path matching program.
+ *
+ * @returns IPRT status code.
+ * @param   pchPattern          The pattern to compile.
+ * @param   cchPattern          The length of the pattern.
+ * @param   pAllocator          Pointer to the instruction allocator & result
+ *                              array.  The compiled "program" starts at
+ *                              PRTPATHMATCHALLOC::paInstructions[PRTPATHMATCHALLOC::iNext]
+ *                              (input iNext value).
+ *
+ * @todo Expose this matching code and also use it for RTDirOpenFiltered
+ */
+static int rtPathMatchCompile(const char *pchPattern, size_t cchPattern, bool fIgnoreCase, PRTPATHMATCHALLOC pAllocator)
+{
+    /** @todo PORTME: big endian. */
+    static const uint8_t s_bmMetaChars[256/8] =
+    {
+        0x00, 0x00, 0x00, 0x00, /*  0 thru 31 */
+        0x10, 0x04, 0x00, 0x80, /* 32 thru 63 */
+        0x00, 0x00, 0x00, 0x08, /* 64 thru 95 */
+        0x00, 0x00, 0x00, 0x00, /* 96 thru 127 */
+        /* UTF-8 multibyte: */
+        0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,  0x00, 0x00, 0x00, 0x00,
+    };
+    Assert(ASMBitTest(s_bmMetaChars, '$')); AssertCompile('$' == 0x24 /*36*/);
+    Assert(ASMBitTest(s_bmMetaChars, '*')); AssertCompile('*' == 0x2a /*42*/);
+    Assert(ASMBitTest(s_bmMetaChars, '?')); AssertCompile('?' == 0x3f /*63*/);
+    Assert(ASMBitTest(s_bmMetaChars, '[')); AssertCompile('[' == 0x5b /*91*/);
+
+    /*
+     * For checking for the first instruction.
+     */
+    uint16_t const iFirst = pAllocator->iNext;
+
+    /*
+     * This is for tracking zero-or-more instructions and for calculating
+     * the minimum amount of input required for it to be considered.
+     */
+    uint16_t aiZeroOrMore[RTPATHMATCH_MAX_ZERO_OR_MORE];
+    uint8_t  cZeroOrMore = 0;
+    size_t   offInput    = 0;
+
+    /*
+     * Loop thru the pattern and translate it into string matching instructions.
+     */
+    for (;;)
+    {
+        /*
+         * Allocate the next instruction.
+         */
+        if (pAllocator->iNext >= pAllocator->cAllocated)
+        {
+            uint32_t cNew = RT_MAX(pAllocator->cAllocated, 1) * 2;
+            void *pvNew = RTMemRealloc(pAllocator->paInstructions, cNew * sizeof(pAllocator->paInstructions[0]));
+            AssertReturn(pvNew, VERR_NO_MEMORY);
+            pAllocator->paInstructions = (PRTPATHMATCHCORE)pvNew;
+            pAllocator->cAllocated     = cNew;
+        }
+        PRTPATHMATCHCORE pInstr = &pAllocator->paInstructions[pAllocator->iNext++];
+        pInstr->pch  = pchPattern;
+        pInstr->cch  = 0;
+        pInstr->uOp2 = 0;
+
+        /*
+         * Special case: End of pattern.
+         */
+        if (!cchPattern)
+        {
+            pInstr->enmOpCode = RTPATHMATCHOP_RETURN_MATCH_IF_AT_END;
+            break;
+        }
+
+        /*
+         * Parse the next bit of the pattern.
+         */
+        char ch = *pchPattern;
+        if (ASMBitTest(s_bmMetaChars, (uint8_t)ch))
+        {
+            /*
+             * Zero or more characters wildcard.
+             */
+            /** @todo bitmap optimziation (index = ch).   */
+            if (ch == '*')
+            {
+                /* Skip extra asterisks. */
+                do
+                {
+                    cchPattern--;
+                    pchPattern++;
+                } while (cchPattern > 0 && *pchPattern == '*');
+
+                /* There is a special optimization for trailing '*'. */
+                pInstr->cch = 1;
+                if (cchPattern == 0)
+                {
+                    pInstr->enmOpCode = iFirst + 1 == pAllocator->iNext
+                                      ? RTPATHMATCHOP_RETURN_MATCH_EXCEPT_DOT_AND_DOTDOT : RTPATHMATCHOP_RETURN_MATCH;
+                    break;
+                }
+
+                pInstr->enmOpCode = iFirst + 1 == pAllocator->iNext
+                                  ? RTPATHMATCHOP_ZERO_OR_MORE_EXCEPT_DOT_AND_DOTDOT : RTPATHMATCHOP_ZERO_OR_MORE;
+                pInstr->uOp2      = (uint16_t)offInput;
+                AssertReturn(cZeroOrMore < RT_ELEMENTS(aiZeroOrMore), VERR_OUT_OF_RANGE);
+                aiZeroOrMore[cZeroOrMore] = (uint16_t)(pInstr - pAllocator->paInstructions);
+
+                /* cchInput unchanged, zero-or-more matches. */
+                continue;
+            }
+
+            /*
+             * Single character wildcard.
+             */
+            if (ch == '?')
+            {
+                /* Count them if more. */
+                uint16_t cchQms = 1;
+                while (cchQms < cchPattern && pchPattern[cchQms] == '?')
+                    cchQms++;
+
+                pInstr->cch = cchQms;
+                pInstr->enmOpCode = cchQms == 1 ? RTPATHMATCHOP_SKIP_ONE_CODEPOINT : RTPATHMATCHOP_SKIP_MULTIPLE_CODEPOINTS;
+
+                cchPattern -= cchQms;
+                pchPattern += cchQms;
+                offInput   += cchQms;
+                continue;
+            }
+
+            /*
+             * Character in set.
+             *
+             * Note that we skip the first char in the set as that is the only place
+             * ']' can be placed if one desires to explicitly include it in the set.
+             * To make life a bit more interesting, [:class:] is allowed inside the
+             * set, so we have to do the counting game to find the end.
+             */
+            if (ch == '[')
+            {
+                if (   cchPattern > 2
+                    && (const char *)memchr(pchPattern + 2, ']', cchPattern) != NULL)
+                {
+
+                    /* Check for not-in. */
+                    bool   fInverted = false;
+                    size_t offStart  = 1;
+                    if (pchPattern[offStart] == '^')
+                    {
+                        fInverted = true;
+                        offStart++;
+                    }
+
+                    /* Special case for ']' as the first char, it doesn't indicate closing then. */
+                    size_t off = offStart;
+                    if (pchPattern[off] == ']')
+                        off++;
+
+                    bool fExtended = false;
+                    while (off < cchPattern)
+                    {
+                        ch = pchPattern[off++];
+                        if (ch == '[')
+                        {
+                            if (off < cchPattern)
+                            {
+                                char chOpen = pchPattern[off];
+                                if (   chOpen == ':'
+                                    || chOpen == '='
+                                    || chOpen == '.')
+                                {
+                                    off++;
+                                    const char *pchFound = (const char *)memchr(&pchPattern[off], ']', cchPattern - off);
+                                    if (   pchFound
+                                        && pchFound[-1] == chOpen)
+                                    {
+                                        fExtended = true;
+                                        off = pchFound - pchPattern + 1;
+                                    }
+                                    else
+                                        AssertFailed();
+                                }
+                            }
+                        }
+                        /* Check for closing. */
+                        else if (ch == ']')
+                            break;
+                        /* Check for range expression, promote to extended if this happens. */
+                        else if (   ch == '-'
+                                 && off != offStart + 1
+                                 && off < cchPattern
+                                 && pchPattern[off] != ']')
+                            fExtended = true;
+                        /* UTF-8 multibyte chars forces us to use the extended version too. */
+                        else if ((uint8_t)ch >= 0x80)
+                            fExtended = true;
+                    }
+
+                    if (ch == ']')
+                    {
+                        pInstr->pch = &pchPattern[offStart];
+                        pInstr->cch = (uint16_t)(off - offStart - 1);
+                        if (!fExtended)
+                            pInstr->enmOpCode = !fInverted
+                                              ? RTPATHMATCHOP_CODEPOINT_IN_SET_ASCII7 : RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_ASCII7;
+                        else
+                            pInstr->enmOpCode = !fInverted
+                                              ? RTPATHMATCHOP_CODEPOINT_IN_SET_EXTENDED
+                                              : RTPATHMATCHOP_CODEPOINT_NOT_IN_SET_EXTENDED;
+                        pchPattern += off;
+                        cchPattern -= off;
+                        offInput   += 1;
+                        continue;
+                    }
+
+                    /* else: invalid, treat it as */
+                    AssertFailed();
+                }
+            }
+            /*
+             * Variable matching.
+             */
+            else if (ch == '$')
+            {
+                const char *pchFound;
+                if (   cchPattern > 3
+                    && pchPattern[1] == '{'
+                    && (pchFound = (const char *)memchr(pchPattern + 2, '}', cchPattern)) != NULL
+                    && pchFound != &pchPattern[2])
+                {
+                    /* skip to the variable name. */
+                    pchPattern += 2;
+                    cchPattern -= 2;
+                    size_t cchVarNm = pchFound - pchPattern;
+
+                    /* Look it up. */
+                    uint32_t iVar;
+                    for (iVar = 0; iVar < RT_ELEMENTS(g_aVariables); iVar++)
+                        if (   g_aVariables[iVar].cchName == cchVarNm
+                            && memcmp(g_aVariables[iVar].pszName, pchPattern, cchVarNm) == 0)
+                            break;
+                    if (iVar < RT_ELEMENTS(g_aVariables))
+                    {
+                        pInstr->uOp2      = (uint16_t)iVar;
+                        pInstr->enmOpCode = !fIgnoreCase ? RTPATHMATCHOP_VARIABLE_VALUE_CMP : RTPATHMATCHOP_VARIABLE_VALUE_ICMP;
+                        pInstr->pch       = pchPattern;             /* not necessary */
+                        pInstr->cch       = (uint16_t)cchPattern;   /* ditto */
+                        pchPattern += cchVarNm + 1;
+                        cchPattern -= cchVarNm + 1;
+                        AssertMsgReturn(!g_aVariables[iVar].fFirstOnly || iFirst + 1 == pAllocator->iNext,
+                                        ("Glob variable '%s' should be first\n", g_aVariables[iVar].pszName),
+                                        VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST);
+                        /* cchInput unchanged, value can be empty. */
+                        continue;
+                    }
+                    AssertMsgFailedReturn(("Unknown path matching variable '%.*s'\n", cchVarNm, pchPattern),
+                                          VERR_PATH_MATCH_UNKNOWN_VARIABLE);
+                }
+            }
+            else
+                AssertFailedReturn(VERR_INTERNAL_ERROR_2); /* broken bitmap / compiler codeset */
+        }
+
+        /*
+         * Plain text.  Look for the next meta char.
+         */
+        uint32_t cchPlain = 1;
+        while (cchPlain < cchPattern)
+        {
+            char const ch = pchPattern[cchPlain];
+            if (!ASMBitTest(s_bmMetaChars, (uint8_t)ch))
+            { /* probable */ }
+            else if (   ch == '?'
+                     || ch == '*')
+                break;
+            else if (ch == '$')
+            {
+                const char *pchFound;
+                if (   cchPattern > cchPlain + 3
+                    && pchPattern[cchPlain + 1] == '{'
+                    && (pchFound = (const char *)memchr(&pchPattern[cchPlain + 2], '}', cchPattern - cchPlain - 2)) != NULL
+                    && pchFound != &pchPattern[cchPlain + 2])
+                break;
+            }
+            else if (ch == '[')
+            {
+                /* We don't put a lot of effort into getting this 100% right here,
+                   no point it complicating things for malformed expressions. */
+                if (   cchPattern > cchPlain + 2
+                    && memchr(&pchPattern[cchPlain + 2], ']', cchPattern - cchPlain - 1) != NULL)
+                    break;
+            }
+            else
+                AssertFailedReturn(VERR_INTERNAL_ERROR_2); /* broken bitmap / compiler codeset */
+            cchPlain++;
+        }
+        pInstr->enmOpCode = !fIgnoreCase ? RTPATHMATCHOP_STRCMP : RTPATHMATCHOP_STRICMP;
+        pInstr->cch       = cchPlain;
+        Assert(pInstr->pch == pchPattern);
+        Assert(pInstr->uOp2 == 0);
+        pchPattern += cchPlain;
+        cchPattern -= cchPlain;
+        offInput   += cchPlain;
+    }
+
+    /*
+     * Optimize zero-or-more matching.
+     */
+    while (cZeroOrMore-- > 0)
+    {
+        PRTPATHMATCHCORE pInstr = &pAllocator->paInstructions[aiZeroOrMore[cZeroOrMore]];
+        pInstr->uOp2 = (uint16_t)(offInput - pInstr->uOp2);
+    }
+
+    /** @todo It's possible to use offInput to inject a instruction for checking
+     *        minimum input length at the start of the program.  Not sure it's
+     *        worth it though, unless it's long a complicated expression... */
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Parses the glob pattern.
+ *
+ * This compiles filename matching programs for each component and determins the
+ * optimal search strategy for them.
+ *
+ * @returns IPRT status code.
+ * @param   pGlob               The glob instance data.
+ * @param   pszPattern          The pattern to parse.
+ * @param   pParsed             The RTPathParse output for the pattern.
+ * @param   fFlags              The glob flags (same as pGlob->fFlags).
+ */
+static int rtPathGlobParse(PRTPATHGLOB pGlob, const char *pszPattern, PRTPATHPARSED pParsed, uint32_t fFlags)
+{
+    AssertReturn(pParsed->cComps > 0, VERR_INVALID_PARAMETER); /* shouldn't happen */
+    uint32_t iComp = 0;
+
+    /*
+     * If we've got a rootspec, mark it as plain.  On platforms with
+     * drive letter and/or UNC we don't allow wildcards or such in
+     * the drive letter spec or UNC server name.  (At least not yet.)
+     */
+    if (RTPATH_PROP_HAS_ROOT_SPEC(pParsed->fProps))
+    {
+        AssertReturn(pParsed->aComps[0].cch < sizeof(pGlob->szPath) - 1, VERR_FILENAME_TOO_LONG);
+        memcpy(pGlob->szPath, &pszPattern[pParsed->aComps[0].off], pParsed->aComps[0].cch);
+        pGlob->offFirstPath = pParsed->aComps[0].off;
+        pGlob->iFirstComp   = iComp = 1;
+    }
+    else
+    {
+        const char * const pszComp = &pszPattern[pParsed->aComps[0].off];
+
+        /*
+         * The tilde is only applicable to the first component, expand it
+         * immediately.
+         */
+        if (   *pszComp == '~'
+            && !(fFlags & RTPATHGLOB_F_NO_TILDE))
+        {
+            if (pParsed->aComps[0].cch == 1)
+            {
+                int rc = RTPathUserHome(pGlob->szPath, sizeof(pGlob->szPath) - 1);
+                AssertRCReturn(rc, rc);
+            }
+            else
+                AssertMsgFailedReturn(("'%.*s' is not supported yet\n", pszComp, pParsed->aComps[0].cch),
+                                      VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED);
+            pGlob->offFirstPath = (uint32_t)RTPathEnsureTrailingSeparator(pGlob->szPath, sizeof(pGlob->szPath));
+            pGlob->iFirstComp   = iComp = 1;
+        }
+    }
+
+    /*
+     * Process the other components.
+     */
+    bool fStarStar = false;
+    for (; iComp < pParsed->cComps; iComp++)
+    {
+        const char *pszComp = &pszPattern[pParsed->aComps[iComp].off];
+        uint16_t    cchComp = pParsed->aComps[iComp].cch;
+        Assert(pGlob->aComps[iComp].fNormal == false);
+
+        pGlob->aComps[iComp].fDir = iComp + 1 < pParsed->cComps || (fFlags & RTPATHGLOB_F_ONLY_DIRS);
+        if (   cchComp != 2
+            || pszComp[0] != '*'
+            || pszComp[1] != '*'
+            || (fFlags & RTPATHGLOB_F_NO_STARSTAR) )
+        {
+            /* Compile the pattern. */
+            uint16_t const iMatchProg = pGlob->MatchInstrAlloc.iNext;
+            pGlob->aComps[iComp].iMatchProg = iMatchProg;
+            int rc = rtPathMatchCompile(pszComp, cchComp, RT_BOOL(fFlags & RTPATHGLOB_F_IGNORE_CASE),
+                                        &pGlob->MatchInstrAlloc);
+            if (RT_FAILURE(rc))
+                return rc;
+
+            /* Check for plain text as well as full variable matching (not applicable after '**'). */
+            uint16_t const cInstructions = pGlob->MatchInstrAlloc.iNext - iMatchProg;
+            if (   cInstructions == 2
+                && !fStarStar
+                && pGlob->MatchInstrAlloc.paInstructions[iMatchProg + 1].enmOpCode == RTPATHMATCHOP_RETURN_MATCH_IF_AT_END)
+            {
+                if (   pGlob->MatchInstrAlloc.paInstructions[iMatchProg].enmOpCode == RTPATHMATCHOP_STRCMP
+                    || pGlob->MatchInstrAlloc.paInstructions[iMatchProg].enmOpCode == RTPATHMATCHOP_STRICMP)
+                    pGlob->aComps[iComp].fPlain  = true;
+                else if (   pGlob->MatchInstrAlloc.paInstructions[iMatchProg].enmOpCode == RTPATHMATCHOP_VARIABLE_VALUE_CMP
+                         || pGlob->MatchInstrAlloc.paInstructions[iMatchProg].enmOpCode == RTPATHMATCHOP_VARIABLE_VALUE_ICMP)
+                {
+                    pGlob->aComps[iComp].fExpVariable = true;
+                    AssertMsgReturn(   iComp == 0
+                                    || !g_aVariables[pGlob->MatchInstrAlloc.paInstructions[iMatchProg].uOp2].fFirstOnly,
+                                    ("Glob variable '%.*s' can only be used as the path component.\n",  cchComp, pszComp),
+                                    VERR_PATH_MATCH_VARIABLE_MUST_BE_FIRST);
+                }
+                else
+                    pGlob->aComps[iComp].fNormal = true;
+            }
+            else
+                pGlob->aComps[iComp].fNormal = true;
+        }
+        else
+        {
+            /* Recursive "**" matching. */
+            pGlob->aComps[iComp].fNormal   = false;
+            pGlob->aComps[iComp].fStarStar = true;
+            AssertReturn(!fStarStar, VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED); /** @todo implement multiple '**' sequences in a pattern. */
+            fStarStar = true;
+        }
+    }
+    pGlob->aComps[pParsed->cComps - 1].fFinal = true;
+
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * This is for skipping overly long directories entries.
+ *
+ * Since our directory entry buffer can hold filenames of RTPATH_MAX bytes, we
+ * can safely skip filenames that are longer.  There are very few file systems
+ * that can actually store filenames longer than 255 bytes at time of coding
+ * (2015-09), and extremely few which can exceed 4096 (RTPATH_MAX) bytes.
+ *
+ * @returns IPRT status code.
+ * @param   hDir        The directory handle.
+ * @param   cbNeeded    The required entry size.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobSkipDirEntry(PRTDIR hDir, size_t cbNeeded)
+{
+    int rc = VERR_BUFFER_OVERFLOW;
+    cbNeeded = RT_ALIGN_Z(cbNeeded, 16);
+    PRTDIRENTRY pDirEntry = (PRTDIRENTRY)RTMemTmpAlloc(cbNeeded);
+    if (pDirEntry)
+    {
+        rc = RTDirRead(hDir, pDirEntry, &cbNeeded);
+        RTMemTmpFree(pDirEntry);
+    }
+    return rc;
+}
+
+
+/**
+ * Adds a result.
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_CALLBACK_RETURN if we can stop searching.
+ *
+ * @param   pGlob       The glob instance data.
+ * @param   cchPath     The number of bytes to add from pGlob->szPath.
+ * @param   uType       The RTDIRENTRYTYPE value.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobAddResult(PRTPATHGLOB pGlob, size_t cchPath, uint8_t uType)
+{
+    if (pGlob->cResults < RTPATHGLOB_MAX_RESULTS)
+    {
+        PRTPATHGLOBENTRY pEntry = (PRTPATHGLOBENTRY)RTMemAlloc(RT_OFFSETOF(RTPATHGLOBENTRY, szPath[cchPath + 1]));
+        if (pEntry)
+        {
+            pEntry->uType   = uType;
+            pEntry->cchPath = (uint16_t)cchPath;
+            memcpy(pEntry->szPath, pGlob->szPath, cchPath);
+            pEntry->szPath[cchPath] = '\0';
+
+            pEntry->pNext  = NULL;
+            *pGlob->ppNext = pEntry;
+            pGlob->ppNext  = &pEntry->pNext;
+            pGlob->cResults++;
+
+            if (!(pGlob->fFlags & RTPATHGLOB_F_FIRST_ONLY))
+                return VINF_SUCCESS;
+            return VINF_CALLBACK_RETURN;
+        }
+        return VERR_NO_MEMORY;
+    }
+    return VERR_TOO_MUCH_DATA;
+}
+
+
+/**
+ * Adds a result, constructing the path from two string.
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_CALLBACK_RETURN if we can stop searching.
+ *
+ * @param   pGlob       The glob instance data.
+ * @param   cchPath     The number of bytes to add from pGlob->szPath.
+ * @param   pchName     The string (usual filename) to append to the szPath.
+ * @param   cchName     The length of the string to append.
+ * @param   uType       The RTDIRENTRYTYPE value.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobAddResult2(PRTPATHGLOB pGlob, size_t cchPath, const char *pchName, size_t cchName,
+                                                 uint8_t uType)
+{
+    if (pGlob->cResults < RTPATHGLOB_MAX_RESULTS)
+    {
+        PRTPATHGLOBENTRY pEntry = (PRTPATHGLOBENTRY)RTMemAlloc(RT_OFFSETOF(RTPATHGLOBENTRY, szPath[cchPath + cchName + 1]));
+        if (pEntry)
+        {
+            pEntry->uType   = uType;
+            pEntry->cchPath = (uint16_t)(cchPath + cchName);
+            memcpy(pEntry->szPath, pGlob->szPath, cchPath);
+            memcpy(&pEntry->szPath[cchPath], pchName, cchName);
+            pEntry->szPath[cchPath + cchName] = '\0';
+
+            pEntry->pNext  = NULL;
+            *pGlob->ppNext = pEntry;
+            pGlob->ppNext  = &pEntry->pNext;
+            pGlob->cResults++;
+
+            if (!(pGlob->fFlags & RTPATHGLOB_F_FIRST_ONLY))
+                return VINF_SUCCESS;
+            return VINF_CALLBACK_RETURN;
+        }
+        return VERR_NO_MEMORY;
+    }
+    return VERR_TOO_MUCH_DATA;
+}
+
+
+/**
+ * Prepares a result, constructing the path from two string.
+ *
+ * The caller must call either rtPathGlobCommitResult or
+ * rtPathGlobRollbackResult to complete the operation.
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_CALLBACK_RETURN if we can stop searching.
+ *
+ * @param   pGlob       The glob instance data.
+ * @param   cchPath     The number of bytes to add from pGlob->szPath.
+ * @param   pchName     The string (usual filename) to append to the szPath.
+ * @param   cchName     The length of the string to append.
+ * @param   uType       The RTDIRENTRYTYPE value.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobAlmostAddResult(PRTPATHGLOB pGlob, size_t cchPath, const char *pchName, size_t cchName,
+                                                      uint8_t uType)
+{
+    if (pGlob->cResults < RTPATHGLOB_MAX_RESULTS)
+    {
+        PRTPATHGLOBENTRY pEntry = (PRTPATHGLOBENTRY)RTMemAlloc(RT_OFFSETOF(RTPATHGLOBENTRY, szPath[cchPath + cchName + 1]));
+        if (pEntry)
+        {
+            pEntry->uType   = uType;
+            pEntry->cchPath = (uint16_t)(cchPath + cchName);
+            memcpy(pEntry->szPath, pGlob->szPath, cchPath);
+            memcpy(&pEntry->szPath[cchPath], pchName, cchName);
+            pEntry->szPath[cchPath + cchName] = '\0';
+
+            pEntry->pNext  = NULL;
+            *pGlob->ppNext = pEntry;
+            /* Note! We don't update ppNext here, that is done in rtPathGlobCommitResult. */
+
+            if (!(pGlob->fFlags & RTPATHGLOB_F_FIRST_ONLY))
+                return VINF_SUCCESS;
+            return VINF_CALLBACK_RETURN;
+        }
+        return VERR_NO_MEMORY;
+    }
+    return VERR_TOO_MUCH_DATA;
+}
+
+
+/**
+ * Commits a pending result from rtPathGlobAlmostAddResult.
+ *
+ * @param   pGlob       The glob instance data.
+ * @param   uType       The RTDIRENTRYTYPE value.
+ */
+static void rtPathGlobCommitResult(PRTPATHGLOB pGlob, uint8_t uType)
+{
+    PRTPATHGLOBENTRY pEntry = *pGlob->ppNext;
+    AssertPtr(pEntry);
+    pEntry->uType = uType;
+    pGlob->ppNext = &pEntry->pNext;
+    pGlob->cResults++;
+}
+
+
+/**
+ * Rolls back a pending result from rtPathGlobAlmostAddResult.
+ *
+ * @param   pGlob       The glob instance data.
+ */
+static void rtPathGlobRollbackResult(PRTPATHGLOB pGlob)
+{
+    PRTPATHGLOBENTRY pEntry = *pGlob->ppNext;
+    AssertPtr(pEntry);
+    RTMemFree(pEntry);
+    *pGlob->ppNext = NULL;
+}
+
+
+
+/**
+ * Whether to call rtPathGlobExecRecursiveVarExp for the next component.
+ *
+ * @returns true / false.
+ * @param   pGlob       The glob instance data.
+ * @param   offPath     The next path offset/length.
+ * @param   iComp       The next component.
+ */
+DECLINLINE(bool) rtPathGlobExecIsExpVar(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+    return pGlob->aComps[iComp].fExpVariable
+        && (  !(pGlob->fFlags & RTPATHGLOB_F_IGNORE_CASE)
+            || (offPath ? !RTFsIsCaseSensitive(pGlob->szPath) : !RTFsIsCaseSensitive(".")) );
+}
+
+/**
+ * Whether to call rtPathGlobExecRecursivePlainText for the next component.
+ *
+ * @returns true / false.
+ * @param   pGlob       The glob instance data.
+ * @param   offPath     The next path offset/length.
+ * @param   iComp       The next component.
+ */
+DECLINLINE(bool) rtPathGlobExecIsPlainText(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+    return pGlob->aComps[iComp].fPlain
+        && (  !(pGlob->fFlags & RTPATHGLOB_F_IGNORE_CASE)
+            || (offPath ? !RTFsIsCaseSensitive(pGlob->szPath) : !RTFsIsCaseSensitive(".")) );
+}
+
+
+/**
+ * Helper for rtPathGlobExecRecursiveVarExp and rtPathGlobExecRecursivePlainText
+ * that compares a file mode mask with dir/no-dir wishes of the caller.
+ *
+ * @returns true if match, false if not.
+ * @param   pGlob       The glob instance data.
+ * @param   fMode       The file mode (only the type is used).
+ */
+DECLINLINE(bool) rtPathGlobExecIsMatchFinalWithFileMode(PRTPATHGLOB pGlob, RTFMODE fMode)
+{
+    if (!(pGlob->fFlags & (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS)))
+        return true;
+    return RT_BOOL(pGlob->fFlags & RTPATHGLOB_F_ONLY_DIRS) == RTFS_IS_DIRECTORY(pGlob->u.ObjInfo.Attr.fMode);
+}
+
+
+/**
+ * Recursive globbing - star-star mode.
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_CALLBACK_RETURN is used to implement RTPATHGLOB_F_FIRST_ONLY.
+ *
+ * @param   pGlob               The glob instance data.
+ * @param   offPath             The current path offset/length.
+ * @param   iComp               The current component.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobExecRecursiveStarStar(PRTPATHGLOB pGlob, size_t offPath, uint32_t iStarStarComp,
+                                                            size_t offStarStarPath)
+{
+    /** @todo implement multi subdir matching. */
+    return VERR_PATH_MATCH_FEATURE_NOT_IMPLEMENTED;
+}
+
+
+
+/**
+ * Recursive globbing - variable expansion optimization.
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_CALLBACK_RETURN is used to implement RTPATHGLOB_F_FIRST_ONLY.
+ *
+ * @param   pGlob               The glob instance data.
+ * @param   offPath             The current path offset/length.
+ * @param   iComp               The current component.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobExecRecursiveVarExp(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+    Assert(iComp < pGlob->pParsed->cComps);
+    Assert(pGlob->szPath[offPath] == '\0');
+    Assert(pGlob->aComps[iComp].fExpVariable);
+    Assert(!pGlob->aComps[iComp].fPlain);
+    Assert(!pGlob->aComps[iComp].fStarStar);
+    Assert(rtPathGlobExecIsExpVar(pGlob, offPath, iComp));
+
+    /*
+     * Fish the variable index out of the first matching instruction.
+     */
+    Assert(      pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].enmOpCode
+              == RTPATHMATCHOP_VARIABLE_VALUE_CMP
+           ||   pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].enmOpCode
+              == RTPATHMATCHOP_VARIABLE_VALUE_ICMP);
+    uint16_t const iVar = pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].uOp2;
+
+    /*
+     * Enumerate all the variable, giving them the plain text treatment.
+     */
+    for (uint32_t iItem = 0; iItem < RTPATHMATCH_MAX_VAR_ITEMS; iItem++)
+    {
+        size_t cch;
+        int rcVar = g_aVariables[iVar].pfnQuery(iItem, &pGlob->szPath[offPath], sizeof(pGlob->szPath) - offPath, &cch,
+                                                &pGlob->MatchCache);
+        if (RT_SUCCESS(rcVar))
+        {
+            Assert(pGlob->szPath[offPath + cch] == '\0');
+
+            int rc = RTPathQueryInfoEx(pGlob->szPath, &pGlob->u.ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+            if (RT_SUCCESS(rc))
+            {
+                if (pGlob->aComps[iComp].fFinal)
+                {
+                    if (rtPathGlobExecIsMatchFinalWithFileMode(pGlob, pGlob->u.ObjInfo.Attr.fMode))
+                    {
+                        rc = rtPathGlobAddResult(pGlob, cch,
+                                                 (pGlob->u.ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
+                                                 >> RTFS_TYPE_DIRENTRYTYPE_SHIFT);
+                        if (rc != VINF_SUCCESS)
+                            return rc;
+                    }
+                }
+                else if (RTFS_IS_DIRECTORY(pGlob->u.ObjInfo.Attr.fMode))
+                {
+                    Assert(pGlob->aComps[iComp].fDir);
+                    cch = RTPathEnsureTrailingSeparator(pGlob->szPath, sizeof(pGlob->szPath));
+                    if (cch > 0)
+                    {
+                        if (rtPathGlobExecIsExpVar(pGlob, cch, iComp + 1))
+                            rc = rtPathGlobExecRecursiveVarExp(pGlob, cch, iComp + 1);
+                        else if (rtPathGlobExecIsPlainText(pGlob, cch, iComp + 1))
+                            rc = rtPathGlobExecRecursivePlainText(pGlob, cch, iComp + 1);
+                        else if (pGlob->aComps[pGlob->iFirstComp].fStarStar)
+                            rc = rtPathGlobExecRecursiveStarStar(pGlob, cch, iComp + 1, cch);
+                        else
+                            rc = rtPathGlobExecRecursiveGeneric(pGlob, cch, iComp + 1);
+                        if (rc != VINF_SUCCESS)
+                            return rc;
+                    }
+                    else
+                        pGlob->cPathOverflows++;
+                }
+            }
+            /* else: file doesn't exist or something else is wrong, ignore this. */
+            if (rcVar == VINF_EOF)
+                return VINF_SUCCESS;
+        }
+        else if (rcVar == VERR_EOF)
+            return VINF_SUCCESS;
+        else if (rcVar != VERR_TRY_AGAIN)
+        {
+            Assert(rcVar == VERR_BUFFER_OVERFLOW);
+            pGlob->cPathOverflows++;
+        }
+    }
+    AssertFailedReturn(VINF_SUCCESS); /* Too many items returned, probably buggy query method. */
+}
+
+
+/**
+ * Recursive globbing - plain text optimization.
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_CALLBACK_RETURN is used to implement RTPATHGLOB_F_FIRST_ONLY.
+ *
+ * @param   pGlob               The glob instance data.
+ * @param   offPath             The current path offset/length.
+ * @param   iComp               The current component.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobExecRecursivePlainText(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+    /*
+     * Instead of recursing, we loop thru adjacent plain text components.
+     */
+    for (;;)
+    {
+        /*
+         * Preconditions.
+         */
+        Assert(iComp < pGlob->pParsed->cComps);
+        Assert(pGlob->szPath[offPath] == '\0');
+        Assert(pGlob->aComps[iComp].fPlain);
+        Assert(!pGlob->aComps[iComp].fExpVariable);
+        Assert(!pGlob->aComps[iComp].fStarStar);
+        Assert(rtPathGlobExecIsPlainText(pGlob, offPath, iComp));
+        Assert(pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].enmOpCode
+                  == RTPATHMATCHOP_STRCMP
+               ||   pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg].enmOpCode
+                  == RTPATHMATCHOP_STRICMP);
+
+        /*
+         * Add the plain text component to the path.
+         */
+        size_t const cch = pGlob->pParsed->aComps[iComp].cch;
+        if (cch + pGlob->aComps[iComp].fDir < sizeof(pGlob->szPath) - offPath)
+        {
+            memcpy(&pGlob->szPath[offPath], &pGlob->pszPattern[pGlob->pParsed->aComps[iComp].off], cch);
+            offPath += cch;
+            pGlob->szPath[offPath] = '\0';
+
+            /*
+             * Check if it exists.
+             */
+            int rc = RTPathQueryInfoEx(pGlob->szPath, &pGlob->u.ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+            if (RT_SUCCESS(rc))
+            {
+                if (pGlob->aComps[iComp].fFinal)
+                {
+                    if (rtPathGlobExecIsMatchFinalWithFileMode(pGlob, pGlob->u.ObjInfo.Attr.fMode))
+                        return rtPathGlobAddResult(pGlob, offPath,
+                                                   (pGlob->u.ObjInfo.Attr.fMode & RTFS_TYPE_MASK)
+                                                   >> RTFS_TYPE_DIRENTRYTYPE_SHIFT);
+                    break;
+                }
+
+                if (RTFS_IS_DIRECTORY(pGlob->u.ObjInfo.Attr.fMode))
+                {
+                    Assert(pGlob->aComps[iComp].fDir);
+                    pGlob->szPath[offPath++] = RTPATH_SLASH;
+                    pGlob->szPath[offPath]   = '\0';
+
+                    iComp++;
+                    if (rtPathGlobExecIsExpVar(pGlob, offPath, iComp))
+                        return rtPathGlobExecRecursiveVarExp(pGlob, offPath, iComp);
+                    if (!rtPathGlobExecIsPlainText(pGlob, offPath, iComp))
+                        return rtPathGlobExecRecursiveGeneric(pGlob, offPath, iComp);
+                    if (pGlob->aComps[pGlob->iFirstComp].fStarStar)
+                        return rtPathGlobExecRecursiveStarStar(pGlob, offPath, iComp, offPath);
+
+                    /* Continue with the next plain text component. */
+                    continue;
+                }
+            }
+            /* else: file doesn't exist or something else is wrong, ignore this. */
+        }
+        else
+            pGlob->cPathOverflows++;
+        break;
+    }
+    return VINF_SUCCESS;
+}
+
+
+/**
+ * Recursive globbing - generic.
+ *
+ * @returns IPRT status code.
+ * @retval  VINF_CALLBACK_RETURN is used to implement RTPATHGLOB_F_FIRST_ONLY.
+ *
+ * @param   pGlob               The glob instance data.
+ * @param   offPath             The current path offset/length.
+ * @param   iComp               The current component.
+ */
+DECL_NO_INLINE(static, int) rtPathGlobExecRecursiveGeneric(PRTPATHGLOB pGlob, size_t offPath, uint32_t iComp)
+{
+    /*
+     * Enumerate entire directory and match each entry.
+     */
+    PRTDIR hDir;
+    int rc = RTDirOpen(&hDir, offPath ? pGlob->szPath : ".");
+    if (RT_SUCCESS(rc))
+    {
+        for (;;)
+        {
+            size_t cch = sizeof(pGlob->u);
+            rc = RTDirRead(hDir, &pGlob->u.DirEntry, &cch);
+            if (RT_SUCCESS(rc))
+            {
+                if (pGlob->aComps[iComp].fFinal)
+                {
+                    /*
+                     * Final component: Check if it matches the current pattern.
+                     */
+                    if (   !(pGlob->fFlags & (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS))
+                        ||    RT_BOOL(pGlob->fFlags & RTPATHGLOB_F_ONLY_DIRS)
+                           == (pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_DIRECTORY)
+                        || pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
+                    {
+                        rc = rtPathMatchExec(pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName,
+                                             &pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg],
+                                             &pGlob->MatchCache);
+                        if (RT_SUCCESS(rc))
+                        {
+                            /* Construct the result. */
+                            if (   pGlob->u.DirEntry.enmType != RTDIRENTRYTYPE_UNKNOWN
+                                || !(pGlob->fFlags & (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS)) )
+                                rc = rtPathGlobAddResult2(pGlob, offPath, pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName,
+                                                          (uint8_t)pGlob->u.DirEntry.enmType);
+                            else
+                            {
+                                rc = rtPathGlobAlmostAddResult(pGlob, offPath,
+                                                               pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName,
+                                                               (uint8_t)RTDIRENTRYTYPE_UNKNOWN);
+                                if (RT_SUCCESS(rc))
+                                {
+                                    RTDirQueryUnknownType((*pGlob->ppNext)->szPath, false /*fFollowSymlinks*/,
+                                                          &pGlob->u.DirEntry.enmType);
+                                    if (   RT_BOOL(pGlob->fFlags & RTPATHGLOB_F_ONLY_DIRS)
+                                        == (pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_DIRECTORY))
+                                        rtPathGlobCommitResult(pGlob, (uint8_t)pGlob->u.DirEntry.enmType);
+                                    else
+                                        rtPathGlobRollbackResult(pGlob);
+                                }
+                            }
+                            if (rc != VINF_SUCCESS)
+                                break;
+                        }
+                        else
+                        {
+                            AssertMsgBreak(rc == VERR_MISMATCH, ("%Rrc\n", rc));
+                            rc = VINF_SUCCESS;
+                        }
+                    }
+                }
+                /*
+                 * Intermediate component: Directories only.
+                 */
+                else if (   pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_DIRECTORY
+                         || pGlob->u.DirEntry.enmType == RTDIRENTRYTYPE_UNKNOWN)
+                {
+                    rc = rtPathMatchExec(pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName,
+                                         &pGlob->MatchInstrAlloc.paInstructions[pGlob->aComps[iComp].iMatchProg],
+                                         &pGlob->MatchCache);
+                    if (RT_SUCCESS(rc))
+                    {
+                        /* Recurse down into the alleged directory. */
+                        cch = offPath + pGlob->u.DirEntry.cbName;
+                        if (cch + 1 < sizeof(pGlob->szPath))
+                        {
+                            memcpy(&pGlob->szPath[offPath], pGlob->u.DirEntry.szName, pGlob->u.DirEntry.cbName);
+                            pGlob->szPath[cch++] = RTPATH_SLASH;
+                            pGlob->szPath[cch]   = '\0';
+
+                            if (rtPathGlobExecIsExpVar(pGlob, cch, iComp + 1))
+                                rc = rtPathGlobExecRecursiveVarExp(pGlob, cch, iComp + 1);
+                            else if (rtPathGlobExecIsPlainText(pGlob, cch, iComp + 1))
+                                rc = rtPathGlobExecRecursivePlainText(pGlob, cch, iComp + 1);
+                            else if (pGlob->aComps[pGlob->iFirstComp].fStarStar)
+                                rc = rtPathGlobExecRecursiveStarStar(pGlob, cch, iComp + 1, cch);
+                            else
+                                rc = rtPathGlobExecRecursiveGeneric(pGlob, cch, iComp + 1);
+                            if (rc != VINF_SUCCESS)
+                                return rc;
+                        }
+                        else
+                            pGlob->cPathOverflows++;
+                    }
+                    else
+                    {
+                        AssertMsgBreak(rc == VERR_MISMATCH, ("%Rrc\n", rc));
+                        rc = VINF_SUCCESS;
+                    }
+                }
+            }
+            /*
+             * RTDirRead failure.
+             */
+            else
+            {
+                /* The end?  */
+                if (rc == VERR_NO_MORE_FILES)
+                    rc = VINF_SUCCESS;
+                /* Try skip the entry if we end up with an overflow (szPath can't hold it either then). */
+                else if (rc == VERR_BUFFER_OVERFLOW)
+                {
+                    pGlob->cPathOverflows++;
+                    rc = rtPathGlobSkipDirEntry(hDir, cch);
+                    if (RT_SUCCESS(rc))
+                        continue;
+                }
+                /* else: Any other error is unexpected and should be reported. */
+                break;
+            }
+        }
+
+        RTDirClose(hDir);
+    }
+    /* Directory doesn't exist or something else is wrong, ignore this. */
+    else
+        rc = VINF_SUCCESS;
+    return rc;
+}
+
+
+/**
+ * Executes a glob search.
+ *
+ * @returns IPRT status code.
+ * @param   pGlob               The glob instance data.
+ */
+static int rtPathGlobExec(PRTPATHGLOB pGlob)
+{
+    Assert(pGlob->offFirstPath < sizeof(pGlob->szPath));
+    Assert(pGlob->szPath[pGlob->offFirstPath] == '\0');
+
+    int rc;
+    if (RT_LIKELY(pGlob->iFirstComp < pGlob->pParsed->cComps))
+    {
+        /*
+         * Call the appropriate function.
+         */
+        if (rtPathGlobExecIsExpVar(pGlob, pGlob->offFirstPath, pGlob->iFirstComp))
+            rc = rtPathGlobExecRecursiveVarExp(pGlob, pGlob->offFirstPath, pGlob->iFirstComp);
+        else if (rtPathGlobExecIsPlainText(pGlob, pGlob->offFirstPath, pGlob->iFirstComp))
+            rc = rtPathGlobExecRecursivePlainText(pGlob, pGlob->offFirstPath, pGlob->iFirstComp);
+        else if (pGlob->aComps[pGlob->iFirstComp].fStarStar)
+            rc = rtPathGlobExecRecursiveStarStar(pGlob, pGlob->offFirstPath, pGlob->iFirstComp, pGlob->offFirstPath);
+        else
+            rc = rtPathGlobExecRecursiveGeneric(pGlob, pGlob->offFirstPath, pGlob->iFirstComp);
+    }
+    else
+    {
+        /*
+         * Special case where we only have a root component or tilde expansion.
+         */
+        Assert(pGlob->offFirstPath > 0);
+        rc = RTPathQueryInfoEx(pGlob->szPath, &pGlob->u.ObjInfo, RTFSOBJATTRADD_NOTHING, RTPATH_F_ON_LINK);
+        if (   RT_SUCCESS(rc)
+            && rtPathGlobExecIsMatchFinalWithFileMode(pGlob, pGlob->u.ObjInfo.Attr.fMode))
+            rc = rtPathGlobAddResult(pGlob, pGlob->offFirstPath,
+                                     (pGlob->u.ObjInfo.Attr.fMode & RTFS_TYPE_MASK) >> RTFS_TYPE_DIRENTRYTYPE_SHIFT);
+        else
+            rc = VINF_SUCCESS;
+    }
+
+    /*
+     * Adjust the status code.  Check for results, hide RTPATHGLOB_F_FIRST_ONLY
+     * status code, and add warning if necessary.
+     */
+    if (pGlob->cResults > 0)
+    {
+        if (rc == VINF_CALLBACK_RETURN)
+            rc = VINF_SUCCESS;
+        if (rc == VINF_SUCCESS)
+        {
+            if (pGlob->cPathOverflows > 0)
+                rc = VINF_BUFFER_OVERFLOW;
+        }
+    }
+    else
+        rc = VERR_FILE_NOT_FOUND;
+
+    return rc;
+}
+
+
+RTDECL(int) RTPathGlob(const char *pszPattern, uint32_t fFlags, PPCRTPATHGLOBENTRY ppHead, uint32_t *pcResults)
+{
+    /*
+     * Input validation.
+     */
+    AssertPtrReturn(ppHead, VERR_INVALID_POINTER);
+    *ppHead = NULL;
+    if (pcResults)
+    {
+        AssertPtrReturn(pcResults, VERR_INVALID_POINTER);
+        *pcResults = 0;
+    }
+    AssertPtrReturn(pszPattern, VERR_INVALID_POINTER);
+    AssertReturn(!(fFlags & ~RTPATHGLOB_F_MASK), VERR_INVALID_FLAGS);
+    AssertReturn((fFlags & (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS)) != (RTPATHGLOB_F_NO_DIRS | RTPATHGLOB_F_ONLY_DIRS),
+                 VERR_INVALID_FLAGS);
+
+    /*
+     * Parse the path.
+     */
+    size_t        cbParsed = RT_OFFSETOF(RTPATHPARSED, aComps[1]); /** @todo 16 after testing */
+    PRTPATHPARSED pParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbParsed);
+    AssertReturn(pParsed, VERR_NO_MEMORY);
+    int rc = RTPathParse(pszPattern, pParsed, cbParsed, RTPATH_STR_F_STYLE_HOST);
+    if (rc == VERR_BUFFER_OVERFLOW)
+    {
+        RTMemTmpFree(pParsed);
+        cbParsed = RT_OFFSETOF(RTPATHPARSED, aComps[pParsed->cComps + 1]);
+        pParsed = (PRTPATHPARSED)RTMemTmpAlloc(cbParsed);
+        AssertReturn(pParsed, VERR_NO_MEMORY);
+
+        rc = RTPathParse(pszPattern, pParsed, cbParsed, RTPATH_STR_F_STYLE_HOST);
+    }
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Check dir slash vs. only/not dir flag.
+         */
+        if (   !(fFlags & RTPATHGLOB_F_NO_DIRS)
+            || (   !(pParsed->fProps & RTPATH_PROP_DIR_SLASH)
+                && (   !(pParsed->fProps & (RTPATH_PROP_ROOT_SLASH | RTPATH_PROP_UNC))
+                    || pParsed->cComps > 1) ) )
+        {
+            if (pParsed->fProps & RTPATH_PROP_DIR_SLASH)
+                fFlags |= RTPATHGLOB_F_ONLY_DIRS;
+
+            /*
+             * Allocate and initialize the glob state data structure.
+             */
+            size_t      cbGlob = RT_OFFSETOF(RTPATHGLOB, aComps[pParsed->cComps + 1]);
+            PRTPATHGLOB pGlob  = (PRTPATHGLOB)RTMemTmpAllocZ(cbGlob);
+            if (pGlob)
+            {
+                pGlob->pszPattern = pszPattern;
+                pGlob->fFlags     = fFlags;
+                pGlob->pParsed    = pParsed;
+                pGlob->ppNext     = &pGlob->pHead;
+                rc = rtPathGlobParse(pGlob, pszPattern, pParsed, fFlags);
+                if (RT_SUCCESS(rc))
+                {
+                    /*
+                     * Execute the search.
+                     */
+                    rc = rtPathGlobExec(pGlob);
+                    if (RT_SUCCESS(rc))
+                    {
+                        *ppHead = pGlob->pHead;
+                        if (pcResults)
+                            *pcResults = pGlob->cResults;
+                    }
+                    else
+                        RTPathGlobFree(pGlob->pHead);
+                }
+
+                RTMemTmpFree(pGlob->MatchInstrAlloc.paInstructions);
+                RTMemTmpFree(pGlob);
+            }
+            else
+                rc = VERR_NO_MEMORY;
+        }
+        else
+            rc = VERR_NOT_FOUND;
+    }
+    RTMemTmpFree(pParsed);
+    return rc;
+
+
+}
+
+
+RTDECL(void) RTPathGlobFree(PCRTPATHGLOBENTRY pHead)
+{
+    PRTPATHGLOBENTRY pCur = (PRTPATHGLOBENTRY)pHead;
+    while (pCur)
+    {
+        PRTPATHGLOBENTRY pNext = pCur->pNext;
+        pCur->pNext = NULL;
+        RTMemFree(pCur);
+        pCur = pNext;
+    }
+}
+
Index: /trunk/src/VBox/Runtime/generic/RTCrStoreCreateSnapshotById-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/RTCrStoreCreateSnapshotById-generic.cpp	(revision 57612)
+++ /trunk/src/VBox/Runtime/generic/RTCrStoreCreateSnapshotById-generic.cpp	(revision 57613)
@@ -146,5 +146,5 @@
     }
     else
-        RTErrInfoSet(pErrInfo, rc, "RTCrStoreCreateInMem failed");
+        RTErrInfoAdd(pErrInfo, rc, "  RTCrStoreCreateInMem failed");
     return rc;
 }
Index: /trunk/src/VBox/Runtime/generic/createtemp-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/createtemp-generic.cpp	(revision 57612)
+++ /trunk/src/VBox/Runtime/generic/createtemp-generic.cpp	(revision 57613)
@@ -235,2 +235,48 @@
 }
 RT_EXPORT_SYMBOL(RTFileCreateTempSecure);
+
+
+RTDECL(int) RTFileOpenTemp(PRTFILE phFile, char *pszFilename, size_t cbFilename, uint64_t fOpen)
+{
+    AssertReturn((fOpen & RTFILE_O_ACTION_MASK) == RTFILE_O_CREATE, VERR_INVALID_FLAGS);
+    AssertReturn(fOpen & RTFILE_O_WRITE, VERR_INVALID_FLAGS);
+
+    /*
+     * Start by obtaining the path to the temporary directory.
+     */
+    int rc = RTPathTemp(pszFilename, cbFilename);
+    if (RT_SUCCESS(rc))
+    {
+        /*
+         * Add a filename pattern.
+         */
+        static char const s_szTemplate[] = "IPRT-XXXXXXXXXXXX.tmp";
+        rc = RTPathAppend(pszFilename, cbFilename, s_szTemplate);
+        if (RT_SUCCESS(rc))
+        {
+            char * const pszX = RTStrEnd(pszFilename, cbFilename) - (sizeof(s_szTemplate) - 1) + 5;
+            unsigned     cXes = sizeof(s_szTemplate) - 1 - 4 - 5;
+            Assert(pszX[0] == 'X'); Assert(pszX[-1] == '-'); Assert(pszX[cXes] == '.');
+
+            /*
+             * Try 10000 times with random names.
+             */
+            unsigned cTriesLeft = 10000;
+            while (cTriesLeft-- > 0)
+            {
+                rtCreateTempFillTemplate(pszX, cXes);
+                rc = RTFileOpen(phFile, pszFilename, fOpen);
+                if (RT_SUCCESS(rc))
+                    return rc;
+            }
+        }
+    }
+
+    if (cbFilename)
+        *pszFilename = '\0';
+    *phFile = NIL_RTFILE;
+    return rc;
+}
+RT_EXPORT_SYMBOL(RTFileOpenTemp);
+
+
Index: /trunk/src/VBox/Runtime/generic/fs-stubs-generic.cpp
===================================================================
--- /trunk/src/VBox/Runtime/generic/fs-stubs-generic.cpp	(revision 57612)
+++ /trunk/src/VBox/Runtime/generic/fs-stubs-generic.cpp	(revision 57613)
@@ -68,5 +68,9 @@
 {
     pProperties->cbMaxComponent = 255;
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
+    pProperties->fCaseSensitive = false;
+#else
     pProperties->fCaseSensitive = true;
+#endif
     pProperties->fCompressed = false;
     pProperties->fFileCompression = false;
@@ -78,2 +82,12 @@
 }
 
+
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
+{
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS) || defined(RT_OS_DARWIN)
+    return false;
+#else
+    return true;
+#endif
+}
+
Index: /trunk/src/VBox/Runtime/r3/nt/fs-nt.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/nt/fs-nt.cpp	(revision 57612)
+++ /trunk/src/VBox/Runtime/r3/nt/fs-nt.cpp	(revision 57613)
@@ -226,4 +226,9 @@
 
 
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
+{
+    return false;
+}
+
 
 RTR3DECL(int) RTFsQueryType(const char *pszFsPath, PRTFSTYPE penmType)
Index: /trunk/src/VBox/Runtime/r3/posix/fs-posix.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/posix/fs-posix.cpp	(revision 57612)
+++ /trunk/src/VBox/Runtime/r3/posix/fs-posix.cpp	(revision 57613)
@@ -153,5 +153,9 @@
              */
             pProperties->cbMaxComponent = StatVFS.f_namemax;
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+            pProperties->fCaseSensitive = false;
+#else
             pProperties->fCaseSensitive = true;
+#endif
             pProperties->fCompressed = false;
             pProperties->fFileCompression = false;
@@ -168,4 +172,14 @@
              pszFsPath, pszFsPath, pProperties, pProperties->cbMaxComponent, pProperties->fReadOnly, rc));
     return rc;
+}
+
+
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
+{
+#if defined(RT_OS_OS2) || defined(RT_OS_WINDOWS)
+    return false;
+#else
+    return true;
+#endif
 }
 
Index: /trunk/src/VBox/Runtime/r3/win/fs-win.cpp
===================================================================
--- /trunk/src/VBox/Runtime/r3/win/fs-win.cpp	(revision 57612)
+++ /trunk/src/VBox/Runtime/r3/win/fs-win.cpp	(revision 57613)
@@ -335,4 +335,10 @@
     RTUtf16Free(pwszFsRoot);
     return rc;
+}
+
+
+RTR3DECL(bool) RTFsIsCaseSensitive(const char *pszFsPath)
+{
+    return false;
 }
 
Index: /trunk/src/VBox/Runtime/testcase/Makefile.kmk
===================================================================
--- /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 57612)
+++ /trunk/src/VBox/Runtime/testcase/Makefile.kmk	(revision 57613)
@@ -96,4 +96,5 @@
 	tstOnce \
 	tstRTPath \
+	tstRTPathGlob \
 	tstRTPipe \
 	tstRTPoll \
@@ -493,4 +494,7 @@
 tstRTPath_SOURCES = tstRTPath.cpp
 
+tstRTPathGlob_TEMPLATE = VBOXR3TSTEXE
+tstRTPathGlob_SOURCES = tstRTPathGlob.cpp
+
 tstRTPipe_TEMPLATE = VBOXR3TSTEXE
 tstRTPipe_SOURCES = tstRTPipe.cpp
Index: /trunk/src/VBox/Runtime/testcase/tstRTPathGlob.cpp
===================================================================
--- /trunk/src/VBox/Runtime/testcase/tstRTPathGlob.cpp	(revision 57613)
+++ /trunk/src/VBox/Runtime/testcase/tstRTPathGlob.cpp	(revision 57613)
@@ -0,0 +1,82 @@
+/* $Id$ */
+/** @file
+ * IPRT Testcase - Manual RTPathGlob test.
+ */
+
+/*
+ * Copyright (C) 2006-2015 Oracle Corporation
+ *
+ * This file is part of VirtualBox Open Source Edition (OSE), as
+ * available from http://www.virtualbox.org. This file is free software;
+ * you can redistribute it and/or modify it under the terms of the GNU
+ * General Public License (GPL) as published by the Free Software
+ * Foundation, in version 2 as it comes in the "COPYING" file of the
+ * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
+ * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
+ *
+ * The contents of this file may alternatively be used under the terms
+ * of the Common Development and Distribution License Version 1.0
+ * (CDDL) only, as it comes in the "COPYING.CDDL" file of the
+ * VirtualBox OSE distribution, in which case the provisions of the
+ * CDDL are applicable instead of those of the GPL.
+ *
+ * You may elect to license modified versions of this file under the
+ * terms and conditions of either the GPL or the CDDL or both.
+ */
+
+
+/*********************************************************************************************************************************
+*   Header Files                                                                                                                 *
+*********************************************************************************************************************************/
+#include <iprt/path.h>
+
+#include <iprt/err.h>
+#include <iprt/string.h>
+#include <iprt/test.h>
+
+
+int main(int argc, char **argv)
+{
+    /*
+     * Init RT+Test.
+     */
+    RTTEST hTest;
+    int rc = RTTestInitExAndCreate(argc, &argv, 0, "tstRTPathGlob", &hTest);
+    if (rc)
+        return rc;
+    RTTestBanner(hTest);
+
+    if (argc <= 1)
+        return RTTestSkipAndDestroy(hTest, "Requires arguments");
+
+
+    /*
+     * Manual glob testing.
+     */
+    for (int i = 1; i < argc; i++)
+    {
+        uint32_t            cResults = UINT32_MAX;
+        PCRTPATHGLOBENTRY   pHead = (PCRTPATHGLOBENTRY)&cResults;
+        rc = RTPathGlob(argv[i], 0, &pHead, &cResults);
+        RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "#%u '%s' -> %Rrc cResult=%u\n", i, argv[i], rc, cResults);
+        if (RT_SUCCESS(rc))
+        {
+            uint32_t iEntry = 0;
+            for (PCRTPATHGLOBENTRY pCur = pHead; pCur; pCur = pCur->pNext, iEntry++)
+            {
+                RTTestPrintf(hTest, RTTESTLVL_ALWAYS, "  #%3u: '%s'\n", iEntry, pCur->szPath);
+                RTTEST_CHECK(hTest, strlen(pCur->szPath) == pCur->cchPath);
+            }
+
+            RTPathGlobFree(pHead);
+        }
+    }
+
+
+    /*
+     * Summary.
+     */
+    return RTTestSummaryAndDestroy(hTest);
+}
+
+
