@@ -65,6 +65,13 @@ static int printe(const char * fmt, ...) {
65
65
return ret;
66
66
}
67
67
68
+ static std::string strftime_fmt (const char * fmt, const std::tm & tm) {
69
+ std::ostringstream oss;
70
+ oss << std::put_time (&tm, fmt);
71
+
72
+ return oss.str ();
73
+ }
74
+
68
75
class Opt {
69
76
public:
70
77
int init (int argc, const char ** argv) {
@@ -698,6 +705,39 @@ class LlamaData {
698
705
return download (url, bn, true );
699
706
}
700
707
708
+ int s3_dl (const std::string & model, const std::string & bn) {
709
+ const size_t slash_pos = model.find (' /' );
710
+ if (slash_pos == std::string::npos) {
711
+ return 1 ;
712
+ }
713
+
714
+ const std::string bucket = model.substr (0 , slash_pos);
715
+ const std::string key = model.substr (slash_pos + 1 );
716
+ const char * access_key = std::getenv (" AWS_ACCESS_KEY_ID" );
717
+ const char * secret_key = std::getenv (" AWS_SECRET_ACCESS_KEY" );
718
+ if (!access_key || !secret_key) {
719
+ printe (" AWS credentials not found in environment\n " );
720
+ return 1 ;
721
+ }
722
+
723
+ // Generate AWS Signature Version 4 headers
724
+ // (Implementation requires HMAC-SHA256 and date handling)
725
+ // Get current timestamp
726
+ const time_t now = time (nullptr );
727
+ const tm tm = *gmtime (&now);
728
+ const std::string date = strftime_fmt (" %Y%m%d" , tm);
729
+ const std::string datetime = strftime_fmt (" %Y%m%dT%H%M%SZ" , tm);
730
+ const std::vector<std::string> headers = {
731
+ " Authorization: AWS4-HMAC-SHA256 Credential=" + std::string (access_key) + " /" + date +
732
+ " /us-east-1/s3/aws4_request" ,
733
+ " x-amz-content-sha256: UNSIGNED-PAYLOAD" , " x-amz-date: " + datetime
734
+ };
735
+
736
+ const std::string url = " https://" + bucket + " .s3.amazonaws.com/" + key;
737
+
738
+ return download (url, bn, true , headers);
739
+ }
740
+
701
741
std::string basename (const std::string & path) {
702
742
const size_t pos = path.find_last_of (" /\\ " );
703
743
if (pos == std::string::npos) {
@@ -738,6 +778,9 @@ class LlamaData {
738
778
rm_until_substring (model_, " github:" );
739
779
rm_until_substring (model_, " ://" );
740
780
ret = github_dl (model_, bn);
781
+ } else if (string_starts_with (model_, " s3://" )) {
782
+ rm_until_substring (model_, " ://" );
783
+ ret = s3_dl (model_, bn);
741
784
} else { // ollama:// or nothing
742
785
rm_until_substring (model_, " ollama.com/library/" );
743
786
rm_until_substring (model_, " ://" );
0 commit comments