Repository: ggml-org/llama.cpp
Pull request: llama-run: Fix model download on Windows

llama-run: Fix model download on Windows
 * fix SSL error (SSL peer certificate or SSH remote key was not OK)
 * fix program crash on std::filesystem::rename


Changed files:
filename: tools/run/run.cpp
patch: @@ -407,6 +407,43 @@ class HttpClient {
         }
 
         std::string output_file_partial;
+
+        if (!output_file.empty()) {
+            output_file_partial = output_file + ".partial";
+        }
+
+        if (download(url, headers, output_file_partial, progress, response_str)) {
+            return 1;
+        }
+
+        if (!output_file.empty()) {
+            try {
+                std::filesystem::rename(output_file_partial, output_file);
+            } catch (const std::filesystem::filesystem_error & e) {
+                printe("Failed to rename '%s' to '%s': %s\n", output_file_partial.c_str(), output_file.c_str(), e.what());
+                return 1;
+            }
+        }
+
+        return 0;
+    }
+
+    ~HttpClient() {
+        if (chunk) {
+            curl_slist_free_all(chunk);
+        }
+
+        if (curl) {
+            curl_easy_cleanup(curl);
+        }
+    }
+
+  private:
+    CURL *              curl  = nullptr;
+    struct curl_slist * chunk = nullptr;
+
+    int download(const std::string & url, const std::vector<std::string> & headers, const std::string & output_file,
+             const bool progress, std::string * response_str = nullptr) {
         curl = curl_easy_init();
         if (!curl) {
             return 1;
@@ -415,8 +452,7 @@ class HttpClient {
         progress_data data;
         File          out;
         if (!output_file.empty()) {
-            output_file_partial = output_file + ".partial";
-            if (!out.open(output_file_partial, "ab")) {
+            if (!out.open(output_file, "ab")) {
                 printe("Failed to open file for writing\n");
 
                 return 1;
@@ -430,35 +466,18 @@ class HttpClient {
         }
 
         set_write_options(response_str, out);
-        data.file_size = set_resume_point(output_file_partial);
+        data.file_size = set_resume_point(output_file);
         set_progress_options(progress, data);
         set_headers(headers);
         CURLcode res = perform(url);
         if (res != CURLE_OK){
             printe("Fetching resource '%s' failed: %s\n", url.c_str(), curl_easy_strerror(res));
             return 1;
         }
-        if (!output_file.empty()) {
-            std::filesystem::rename(output_file_partial, output_file);
-        }
 
         return 0;
     }
 
-    ~HttpClient() {
-        if (chunk) {
-            curl_slist_free_all(chunk);
-        }
-
-        if (curl) {
-            curl_easy_cleanup(curl);
-        }
-    }
-
-  private:
-    CURL *              curl  = nullptr;
-    struct curl_slist * chunk = nullptr;
-
     void set_write_options(std::string * response_str, const File & out) {
         if (response_str) {
             curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, capture_data);
@@ -507,6 +526,9 @@ class HttpClient {
         curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
         curl_easy_setopt(curl, CURLOPT_DEFAULT_PROTOCOL, "https");
         curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1L);
+#ifdef _WIN32
+        curl_easy_setopt(curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_NATIVE_CA);
+#endif
         return curl_easy_perform(curl);
     }