2
#include <hash_table.h>
9
#include <b64_encode.h>
13
#define HEADER_LINE_MAX 10240
15
enum s3_message_type {
25
enum s3_message_type type;
31
struct list* amz_headers;
35
char authorization[55];
38
static char *s3_endpoint = "s3.amazonaws.com";
39
static char *s3_address = "72.21.202.66";
40
static int s3_timeout = 60;
43
struct amz_header_object* amz_new_header(enum amz_header_type type, const char* custom_type, const char* value) {
44
struct amz_header_object *amz;
45
amz = malloc(sizeof(*amz));
47
if(type == AMZ_CUSTOM_HEADER ) {
48
amz->custom_type = strdup(custom_type);
49
} else amz->custom_type = NULL;
51
amz->value = strdup(value);
55
const char * amz_get_header(enum amz_header_type type, const char* custom_type) {
56
static const char amz_header_acl[] = "x-amz-acl";
57
static const char amz_header_mfa[] = "x-amz-mfa";
60
return amz_header_acl;
62
return amz_header_mfa;
68
int amz_header_comp(const void *a, const void *b) {
69
const struct amz_header_object *one, *two;
70
const char *header1, *header2;
72
one = (struct amz_header_object *)a;
73
two = (struct amz_header_object *)b;
75
header1 = amz_get_header(one->type, one->custom_type);
76
header2 = amz_get_header(two->type, two->custom_type);
78
result = strcmp(header1, header2);
79
if(result) return result;
80
return strcmp(one->value, two->value);
83
int sign_message(struct s3_message* mesg, const char* user, const char * key) {
87
struct amz_header_object *amz;
88
struct list *amz_headers;
89
char digest[SHA1_DIGEST_LENGTH];
90
char string[SHA1_DIGEST_LENGTH*2];
92
memset(digest, 0, SHA1_DIGEST_LENGTH);
93
memset(string, 0, SHA1_DIGEST_LENGTH*2);
118
if(mesg->content_md5) sign_str_len += strlen(mesg->content_md5);
120
if(mesg->content_type) sign_str_len += strlen(mesg->content_type);
123
strftime(date, 1024, "%a, %d %b %Y %H:%M:%S %Z", gmtime(&mesg->date));
124
sign_str_len += strlen(date) + 1;
126
if(mesg->amz_headers) {
127
list_first_item(mesg->amz_headers);
128
while( (amz = (struct amz_header_object *)list_next_item(mesg->amz_headers)) ) {
129
if(amz->type < AMZ_CUSTOM_HEADER) continue;
131
case AMZ_CUSTOM_HEADER:
132
if(!amz->custom_type) return -1;
133
sign_str_len += strlen(amz->custom_type) + 1;
136
sign_str_len += strlen(amz_get_header(amz->type, amz->custom_type)) + 1;
139
if(!amz->value) return -1;
140
sign_str_len += strlen(amz->value) + 1;
143
if(!mesg->bucket || !mesg->path) {
146
sign_str_len += 1 + strlen(mesg->bucket) + 1 + strlen(mesg->path) + 1;
148
sign_str = malloc(sign_str_len);
149
if(!sign_str) return -1;
150
memset(sign_str, 0, sign_str_len);
154
sprintf(sign_str, "GET\n");
157
sprintf(sign_str, "POST\n");
160
sprintf(sign_str, "PUT\n");
163
sprintf(sign_str, "DELETE\n");
166
sprintf(sign_str, "HEAD\n");
169
sprintf(sign_str, "PUT\n");
173
if(mesg->content_md5) sprintf(sign_str, "%s%s\n", sign_str,mesg->content_md5);
174
else sprintf(sign_str, "%s\n", sign_str);
175
if(mesg->content_type) sprintf(sign_str, "%s%s\n", sign_str, mesg->content_type);
176
else sprintf(sign_str, "%s\n", sign_str);
177
sprintf(sign_str, "%s%s", sign_str, date);
179
if(mesg->amz_headers) {
180
amz_headers = list_sort(list_duplicate(mesg->amz_headers), &amz_header_comp);
181
list_first_item(amz_headers);
183
char* c_ctype = NULL;
184
while( (amz = (struct amz_header_object *)list_next_item(amz_headers)) ) {
185
if(amz->type < AMZ_CUSTOM_HEADER) continue;
186
if(c_type != amz->type) {
188
c_ctype = amz->custom_type;
189
sprintf(sign_str, "%s\n%s:%s", sign_str, amz_get_header(amz->type, amz->custom_type), amz->value);
191
} else if(c_type == AMZ_CUSTOM_HEADER && strcmp(c_ctype, amz->custom_type)) {
192
c_ctype = amz->custom_type;
193
sprintf(sign_str, "%s\n%s:%s", sign_str, amz->custom_type, amz->value);
195
sprintf(sign_str, "%s,%s", sign_str, amz->value);
199
list_delete(amz_headers);
202
sprintf(sign_str, "%s\n/%s%s", sign_str, mesg->bucket, mesg->path);
203
if((result = hmac_sha1(sign_str, strlen(sign_str), key, strlen(key), (unsigned char*)digest))) return result;
205
hmac_sha1(sign_str, strlen(sign_str), key, strlen(key), (unsigned char*)digest);
206
b64_encode(digest, SHA1_DIGEST_LENGTH, string, SHA1_DIGEST_LENGTH*2);
208
sprintf(mesg->authorization, "AWS %s:%s", user, string);
214
int s3_message_to_string(struct s3_message *mesg, char** text) {
216
char *msg_str = NULL;
218
struct amz_header_object *amz;
222
msg_str_len = 4 + 11;
225
msg_str_len = 5 + 11;
228
msg_str_len = 4 + 11;
231
msg_str_len = 7 + 11;
234
msg_str_len = 5 + 11;
237
msg_str_len = 4 + 11;
240
fprintf(stderr, "Invalid Message Type\n");
244
if(mesg->path) msg_str_len += strlen(mesg->path) + 1;
246
fprintf(stderr, "no message path\n");
249
if(mesg->bucket) msg_str_len += 6 + strlen(mesg->bucket) + 1 + strlen(s3_endpoint) + 1;
251
fprintf(stderr, "no message bucket\n");
254
strftime(date, 1024, "%a, %d %b %Y %H:%M:%S %Z", gmtime(&mesg->date));
255
//strftime(date, 1024, "%c %Z", gmtime(&mesg->date));
256
msg_str_len += 6 + strlen(date) + 2;
258
if(mesg->content_type) msg_str_len += 14 + strlen(mesg->content_type) + 2;
260
{ int len = mesg->content_length;
268
if(mesg->content_md5) msg_str_len += 13 + strlen(mesg->content_md5) + 2;
270
if(mesg->amz_headers) {
271
list_first_item(mesg->amz_headers);
272
while( (amz = (struct amz_header_object *)list_next_item(mesg->amz_headers)) ) {
274
case AMZ_CUSTOM_HEADER:
275
if(!amz->custom_type) {
276
fprintf(stderr, "no custom type defined for AMZ_CUSTOM_HEADER\n");
279
msg_str_len += strlen(amz->custom_type) + 2;
282
msg_str_len += strlen(amz_get_header(amz->type, amz->custom_type)) + 2;
286
fprintf(stderr, "no value for amz_header\n");
289
msg_str_len += strlen(amz->value) + 2;
293
msg_str_len += 72; //Authorization
295
if(mesg->expect) msg_str_len += 22;
297
msg_str = (char*)malloc(msg_str_len + 1);
299
fprintf(stderr, "malloc(%d) failed for msg_string\n", msg_str_len);
302
memset(msg_str, 0, msg_str_len);
306
sprintf(msg_str, "GET ");
309
sprintf(msg_str, "POST ");
312
sprintf(msg_str, "PUT ");
315
sprintf(msg_str, "DELETE ");
318
sprintf(msg_str, "HEAD ");
321
sprintf(msg_str, "PUT ");
325
sprintf(msg_str, "%s%s HTTP/1.1\r\n", msg_str, mesg->path);
326
sprintf(msg_str, "%sHost: %s.%s\r\n", msg_str, mesg->bucket, s3_endpoint);
327
sprintf(msg_str, "%sDate: %s\r\n", msg_str, date);
328
if(mesg->content_type) sprintf(msg_str, "%sContent-Type: %s\r\n", msg_str, mesg->content_type);
329
sprintf(msg_str, "%sContent-Length: %d\r\n", msg_str, mesg->content_length);
330
if(mesg->content_md5) sprintf(msg_str, "%sContent-MD5: %s\r\n", msg_str, mesg->content_md5);
332
if(mesg->amz_headers) {
333
list_first_item(mesg->amz_headers);
334
while( (amz = (struct amz_header_object *)list_next_item(mesg->amz_headers)) ) {
336
case AMZ_CUSTOM_HEADER:
337
sprintf(msg_str, "%s%s: %s\r\n", msg_str, amz->custom_type, amz->value);
340
sprintf(msg_str, "%s%s: %s\r\n", msg_str, amz_get_header(amz->type, amz->custom_type), amz->value);
345
sprintf(msg_str, "%sAuthorization: %s\r\n", msg_str, mesg->authorization);
347
if(mesg->expect) sprintf(msg_str, "%sExpect: 100-continue\r\n", msg_str);
348
sprintf(msg_str, "%s\r\n", msg_str);
355
int s3_mk_bucket(char* bucketname, enum amz_base_perm perms, const char* access_key_id, const char* access_key) {
358
struct amz_header_object *amz;
359
time_t stoptime = time(0)+s3_timeout;
360
struct s3_message mesg;
362
char response[HEADER_LINE_MAX];
365
if(!access_key_id || !access_key || !s3_endpoint) return -1;
367
mesg.type = S3_MESG_PUT;
369
mesg.bucket = bucketname;
370
mesg.content_length = 0;
371
mesg.content_type = NULL;
372
mesg.content_md5 = NULL;
377
case AMZ_PERM_PRIVATE: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "private"); break;
378
case AMZ_PERM_PUBLIC_READ: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "public-read"); break;
379
case AMZ_PERM_PUBLIC_WRITE: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "public-read-write"); break;
380
case AMZ_PERM_AUTH_READ: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "authenticated-read"); break;
381
case AMZ_PERM_BUCKET_READ: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "bucket-owner-read"); break;
382
case AMZ_PERM_BUCKET_FULL: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "bucket-owner-full-control"); break;
385
mesg.amz_headers = list_create();
386
list_push_tail(mesg.amz_headers, amz);
389
sign_message(&mesg, access_key_id, access_key);
390
length = s3_message_to_string(&mesg, &text);
391
list_free(mesg.amz_headers);
392
list_delete(mesg.amz_headers);
394
server = link_connect(s3_address, 80, stoptime);
395
if(!server) return -1;
397
link_putlstring(server, text, length, stoptime);
400
link_readline(server, response, HEADER_LINE_MAX, stoptime);
401
if(strcmp(response, "HTTP/1.1 200 OK")) {
402
// Error: transfer failed; close connection and return failure
403
//fprintf(stderr, "Error: create bucket failed\nResponse: %s\n", response);
408
//fprintf(stderr, "Response:\n");
410
// fprintf(stderr, "\t%s\n", response);
411
if(!strcmp(response, "Server: AmazonS3")) break;
412
} while(link_readline(server, response, HEADER_LINE_MAX, stoptime));
418
int s3_rm_bucket(char* bucketname, const char* access_key_id, const char* access_key) {
419
struct s3_message mesg;
421
time_t stoptime = time(0)+s3_timeout;
422
char response[HEADER_LINE_MAX];
427
if(!access_key_id || !access_key || !s3_endpoint) return -1;
429
mesg.type = S3_MESG_DELETE;
431
mesg.bucket = bucketname;
432
mesg.content_type = NULL;
433
mesg.content_md5 = NULL;
434
mesg.content_length = 0;
437
mesg.amz_headers = NULL;
439
server = link_connect(s3_address, 80, stoptime);
440
if(!server) return -1;
442
sign_message(&mesg, access_key_id, access_key);
443
length = s3_message_to_string(&mesg, &text);
445
link_putlstring(server, text, length, stoptime);
448
link_readline(server, response, HEADER_LINE_MAX, stoptime);
449
if(strcmp(response, "HTTP/1.1 204 No Content")) {
450
// Error: transfer failed; close connection and return failure
451
//fprintf(stderr, "Error: delete bucket failed\nResponse: %s\n", response);
456
//fprintf(stderr, "Response:\n");
458
// fprintf(stderr, "\t%s\n", response);
459
if(!strcmp(response, "Server: AmazonS3")) break;
460
} while(link_readline(server, response, HEADER_LINE_MAX, stoptime));
466
int s3_ls_bucket(char* bucketname, struct list* dirents, const char* access_key_id, const char* access_key) {
467
struct s3_message mesg;
469
time_t stoptime = time(0)+s3_timeout;
470
char response[HEADER_LINE_MAX];
471
char path[HEADER_LINE_MAX];
476
if(!access_key_id || !access_key || !s3_endpoint) return -1;
479
mesg.type = S3_MESG_GET;
481
mesg.bucket = bucketname;
482
mesg.content_type = NULL;
483
mesg.content_md5 = NULL;
484
mesg.content_length = 0;
487
mesg.amz_headers = NULL;
489
server = link_connect(s3_address, 80, stoptime);
490
if(!server) return -1;
494
char *buffer, *temp, *start, *end, *last;
497
sign_message(&mesg, access_key_id, access_key);
498
length = s3_message_to_string(&mesg, &text);
499
// fprintf(stderr, "Request:\n%s\n", text);
500
link_putlstring(server, text, length, stoptime);
503
link_readline(server, response, HEADER_LINE_MAX, stoptime);
505
if(strcmp(response, "HTTP/1.1 200 OK")) {
506
// Error: transfer failed; close connection and return failure
507
//fprintf(stderr, "Error: list bucket failed\nResponse: %s\n", response);
514
if(!strncmp(response, "Content-Length:", 14)) sscanf(response, "Content-Length: %d", &length);
515
if(!strcmp(response, "Transfer-Encoding: chunked")) length = 0;
516
if(!strcmp(response, "Server: AmazonS3")) break;
517
} while(link_readline(server, response, HEADER_LINE_MAX, stoptime));
518
link_readline(server, response, HEADER_LINE_MAX, stoptime);
521
buffer = malloc(length+1);
522
link_read(server, buffer, length, stoptime);
528
link_readline(server, response, HEADER_LINE_MAX, stoptime);
529
sscanf(response, "%x", &clen);
530
//link_readline(server, response, HEADER_LINE_MAX, stoptime);
532
buffer = malloc(clen+1);
533
link_read(server, buffer, clen, stoptime);
534
link_readline(server, response, HEADER_LINE_MAX, stoptime);
535
list_push_tail(buf, buffer);
539
buffer = malloc(length+1);
541
while((temp = list_pop_head(buf))) {
542
sprintf(buffer, "%s%s", buffer, temp);
548
sscanf(buffer, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\r\n<ListBucketResult xmlns=\"http://s3.amazonaws.com/doc/2006-03-01/\"><Name>%*[^<]</Name><Prefix></Prefix><Marker></Marker><MaxKeys>%d</MaxKeys><IsTruncated>%[^<]</IsTruncated>", &keys, trunc);
549
if(!strcmp(trunc, "false")) done = 1;
551
while( (start = strstr(temp, "<Contents>")) ) {
552
struct s3_dirent_object *d;
554
char display_name[1024];
555
end = strstr(start, "</Contents>");
558
d = malloc(sizeof(*d));
560
sscanf(start, "<Contents><Key>%[^<]</Key><LastModified>%d-%d-%dT%d:%d:%d.%*dZ</LastModified><ETag>"%[^&]"</ETag><Size>%d</Size><Owner><ID>%[^<]</ID><DisplayName>%[^<]</DisplayName></Owner>", d->key, &date.tm_year, &date.tm_mon, &date.tm_mday, &date.tm_hour, &date.tm_min, &date.tm_sec, d->digest, &d->size, d->owner, display_name);
561
d->display_name = strdup(display_name);
563
d->last_modified = mktime(&date);
564
list_push_tail(dirents, d);
575
int s3_getacl(char* bucketname, char* filename, char* owner, struct hash_table* acls, const char* access_key_id, const char* access_key) {
576
struct s3_message mesg;
578
time_t stoptime = time(0)+s3_timeout;
579
char path[HEADER_LINE_MAX];
580
char response[HEADER_LINE_MAX];
586
if(!s3_endpoint) return -1;
587
if(filename) sprintf(path, "%s?acl", filename);
588
else sprintf(path, "/?acl");
590
mesg.type = S3_MESG_GET;
592
mesg.bucket = bucketname;
593
mesg.content_type = NULL;
594
mesg.content_md5 = NULL;
595
mesg.content_length = 0;
598
mesg.amz_headers = NULL;
600
server = link_connect(s3_address, 80, stoptime);
601
if(!server) return -1;
603
sign_message(&mesg, access_key_id, access_key);
604
length = s3_message_to_string(&mesg, &text);
606
link_putlstring(server, text, length, stoptime);
609
link_readline(server, response, HEADER_LINE_MAX, stoptime);
610
if(strcmp(response, "HTTP/1.1 200 OK")) {
611
// Error: transfer failed; close connection and return failure
612
//fprintf(stderr, "Error: request file failed\nResponse: %s\n", response);
618
if(!strncmp(response, "Content-Length:", 14)) sscanf(response, "Content-Length: %d", &length);
619
if(!strcmp(response, "Transfer-Encoding: chunked")) length = 0;
620
if(!strcmp(response, "Server: AmazonS3")) break;
621
} while(link_readline(server, response, HEADER_LINE_MAX, stoptime));
622
link_readline(server, response, HEADER_LINE_MAX, stoptime);
625
text = malloc(length+1);
626
link_read(server, text, length, stoptime);
633
link_readline(server, response, HEADER_LINE_MAX, stoptime);
634
sscanf(response, "%x", &clen);
635
//link_readline(server, response, HEADER_LINE_MAX, stoptime);
637
text = malloc(clen+1);
638
link_read(server, text, clen, stoptime);
639
link_readline(server, response, HEADER_LINE_MAX, stoptime);
640
list_push_tail(buf, text);
644
text = malloc(length+1);
646
while((temp = list_pop_head(buf))) {
647
sprintf(text, "%s%s", text, temp);
654
if(owner) sscanf(strstr(text, "<Owner>"), "<Owner><ID>%[^<]</ID>", owner);
656
while( (start = strstr(temp, "<Grant>")) ) {
658
char display_name[1024];
659
char permission[1024];
661
struct s3_acl_object *acl;
664
end = strstr(start, "</Grant>");
668
memset(display_name, 0, 1024);
670
if( sscanf(start, "<Grant><Grantee %*[^>]><ID>%[^<]</ID><DisplayName>%[^<]</DisplayName></Grantee><Permission>%[^<]</Permission></Grantee>", id, display_name, permission) != 3 ) {
672
sscanf(start, "<Grant><Grantee %*[^>]><URI>http://acs.amazonaws.com/groups/global/%[^<]</URI></Grantee><Permission>%[^<]</Permission></Grantee>", id, permission);
675
if( !(acl = hash_table_lookup(acls, id)) ) {
676
acl = malloc(sizeof(*acl));
677
acl->acl_type = type;
678
if(*display_name) acl->display_name = strdup(display_name);
679
else acl->display_name = NULL;
681
hash_table_insert(acls, id, acl);
684
if(!strcmp(permission, "FULL_CONTROL")) {
685
acl->perm = acl->perm | S3_ACL_FULL_CONTROL;
686
} else if(!strcmp(permission, "READ")) {
687
acl->perm = acl->perm | S3_ACL_READ;
688
} else if(!strcmp(permission, "WRITE")) {
689
acl->perm = acl->perm | S3_ACL_WRITE;
690
} else if(!strcmp(permission, "READ_ACP")) {
691
acl->perm = acl->perm | S3_ACL_READ_ACP;
692
} else if(!strcmp(permission, "WRITE_ACP")) {
693
acl->perm = acl->perm | S3_ACL_WRITE_ACP;
701
// NOT IMPLEMENTED YET
702
int s3_setacl(char* bucketname, char *filename, const char* owner, struct hash_table* acls, const char* access_key_id, const char* access_key) {
703
struct s3_message mesg;
705
time_t stoptime = time(0)+s3_timeout;
706
char path[HEADER_LINE_MAX];
707
char response[HEADER_LINE_MAX];
711
struct s3_acl_object *acl;
713
if(!s3_endpoint) return -1;
714
if(filename) sprintf(path, "%s?acl", filename);
716
sprintf(path, "/?acl");
719
mesg.content_length = 39 + 32 + strlen(owner) + 32;
720
hash_table_firstkey(acls);
721
while(hash_table_nextkey(acls, &id, (void**)&acl)) {
724
switch(acl->acl_type) {
726
glength = 140+strlen(id);
729
glength = 135+strlen(id);
732
glength = 107+strlen(id);
735
if(acl->perm & S3_ACL_FULL_CONTROL) mesg.content_length += 40 + glength + 12;
736
if(acl->perm & S3_ACL_READ) mesg.content_length += 40 + glength + 4;
737
if(acl->perm & S3_ACL_WRITE) mesg.content_length += 40 + glength + 5;
738
if(acl->perm & S3_ACL_READ_ACP) mesg.content_length += 40 + glength + 8;
739
if(acl->perm & S3_ACL_WRITE_ACP) mesg.content_length += 40 + glength + 9;
741
mesg.content_length += 43;
743
mesg.type = S3_MESG_PUT;
745
mesg.bucket = bucketname;
746
mesg.content_type = NULL;
747
mesg.content_md5 = NULL;
750
mesg.amz_headers = NULL;
752
server = link_connect(s3_address, 80, stoptime);
753
if(!server) return -1;
755
sign_message(&mesg, access_key_id, access_key);
756
length = s3_message_to_string(&mesg, &text);
758
fprintf(stderr, "Message:\n%s\n", text);
759
link_putlstring(server, text, length, stoptime);
762
link_putliteral(server, "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n", stoptime);
763
link_putliteral(server, "<AccessControlPolicy><Owner><ID>", stoptime);
764
link_putstring(server, owner, stoptime);
765
link_putliteral(server, "</ID></Owner><AccessControlList>", stoptime);
767
hash_table_firstkey(acls);
768
while(hash_table_nextkey(acls, &id, (void**)&acl)) {
769
char grantee[HEADER_LINE_MAX];
770
char grant[HEADER_LINE_MAX];
772
switch(acl->acl_type) {
774
sprintf(grantee, "<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"Group\"><URI>http://acs.amazonaws.com/groups/global/%s</URI></Grantee>", id);
777
sprintf(grantee, "<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"AmazonCustomerByEmail\"><EmailAddress>%s</EmailAddress></Grantee>", id);
780
sprintf(grantee, "<Grantee xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" xsi:type=\"CanonicalUser\"><ID>%s</ID></Grantee>", id);
783
if(acl->perm & S3_ACL_FULL_CONTROL) {
784
link_putfstring(server, grant, "<Grant>%s<Permission>FULL_CONTROL</Permission></Grant>", stoptime, grantee);
786
if(acl->perm & S3_ACL_READ) {
787
link_putfstring(server, grant, "<Grant>%s<Permission>READ</Permission></Grant>", stoptime, grantee);
789
if(acl->perm & S3_ACL_WRITE) {
790
link_putfstring(server, grant, "<Grant>%s<Permission>WRITE</Permission></Grant>", stoptime, grantee);
792
if(acl->perm & S3_ACL_READ_ACP) {
793
link_putfstring(server, grant, "<Grant>%s<Permission>READ_ACP</Permission></Grant>", stoptime, grantee);
795
if(acl->perm & S3_ACL_WRITE_ACP) {
796
link_putfstring(server, grant, "<Grant>%s<Permission>WRITE_ACP</Permission></Grant>", stoptime, grantee);
800
link_putliteral(server, "</AccessControlList></AccessControlPolicy>\n", stoptime);
802
link_readline(server, response, HEADER_LINE_MAX, stoptime);
803
if(strcmp(response, "HTTP/1.1 200 OK")) {
804
// Error: transfer failed; close connection and return failure
805
fprintf(stderr, "Error: send file failed\nResponse: %s\n", response);
810
// fprintf(stderr, "Response:\n");
812
// fprintf(stderr, "\t%s\n", response);
813
if(!strcmp(response, "Server: AmazonS3")) break;
814
} while(link_readline(server, response, HEADER_LINE_MAX, stoptime));
823
int s3_put_file(const char* localname, char* remotename, char* bucketname, enum amz_base_perm perms, const char* access_key_id, const char* access_key) {
825
struct amz_header_object *amz;
826
time_t stoptime = time(0)+s3_timeout;
827
struct s3_message mesg;
830
char response[HEADER_LINE_MAX];
834
if(!access_key_id || !access_key || !s3_endpoint) return -1;
836
if(stat(localname, &st)) return -1;
838
mesg.type = S3_MESG_PUT;
839
mesg.path = remotename;
840
mesg.bucket = bucketname;
841
mesg.content_type = NULL;
842
mesg.content_md5 = NULL;
843
mesg.content_length = st.st_size;
846
mesg.amz_headers = NULL;
849
case AMZ_PERM_PRIVATE: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "private"); break;
850
case AMZ_PERM_PUBLIC_READ: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "public-read"); break;
851
case AMZ_PERM_PUBLIC_WRITE: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "public-read-write"); break;
852
case AMZ_PERM_AUTH_READ: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "authenticated-read"); break;
853
case AMZ_PERM_BUCKET_READ: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "bucket-owner-read"); break;
854
case AMZ_PERM_BUCKET_FULL: amz = amz_new_header(AMZ_HEADER_ACL, NULL, "bucket-owner-full-control"); break;
858
mesg.amz_headers = list_create();
859
if(!mesg.amz_headers) return -1;
860
list_push_tail(mesg.amz_headers, amz);
862
sign_message(&mesg, access_key_id, access_key);
863
length = s3_message_to_string(&mesg, &text);
864
list_free(mesg.amz_headers);
865
list_delete(mesg.amz_headers);
867
server = link_connect(s3_address, 80, stoptime);
868
if(!server) return -1;
870
link_putlstring(server, text, length, stoptime);
873
link_readline(server, response, HEADER_LINE_MAX, stoptime);
874
if(strcmp(response, "HTTP/1.1 100 Continue")) {
875
// Error: Invalid Headers; close connection and return failure
879
link_readline(server, response, HEADER_LINE_MAX, stoptime);
881
infile = fopen(localname, "r");
882
link_stream_from_file(server, infile, mesg.content_length, stoptime);
884
//link_putliteral(server, "\r\n\r\n", stoptime);
886
link_readline(server, response, HEADER_LINE_MAX, stoptime);
887
if(strcmp(response, "HTTP/1.1 200 OK")) {
888
// Error: transfer failed; close connection and return failure
889
//fprintf(stderr, "Error: send file failed\nResponse: %s\n", response);
894
//fprintf(stderr, "Response:\n");
896
// fprintf(stderr, "\t%s\n", response);
897
if(!strcmp(response, "Server: AmazonS3")) break;
898
} while(link_readline(server, response, HEADER_LINE_MAX, stoptime));
905
int s3_get_file(const char* localname, struct s3_dirent_object *dirent, char* remotename, char* bucketname, const char* access_key_id, const char* access_key) {
906
struct s3_message mesg;
908
time_t stoptime = time(0)+s3_timeout;
909
char response[HEADER_LINE_MAX];
914
if(!access_key_id || !access_key || !s3_endpoint) return -1;
916
mesg.type = S3_MESG_GET;
917
mesg.path = remotename;
918
mesg.bucket = bucketname;
919
mesg.content_type = NULL;
920
mesg.content_md5 = NULL;
921
mesg.content_length = 0;
924
mesg.amz_headers = NULL;
926
server = link_connect(s3_address, 80, stoptime);
927
if(!server) return -1;
929
sign_message(&mesg, access_key_id, access_key);
930
length = s3_message_to_string(&mesg, &text);
931
//fprintf(stderr, "message: %s\n", text);
933
link_putlstring(server, text, length, stoptime);
936
link_readline(server, response, HEADER_LINE_MAX, stoptime);
937
if(strcmp(response, "HTTP/1.1 200 OK")) {
938
// Error: transfer failed; close connection and return failure
939
//fprintf(stderr, "Error: request file failed\nResponse: %s\n", response);
944
//fprintf(stderr, "Response:\n");
946
// fprintf(stderr, "\t%s\n", response);
947
if(!strncmp(response, "Content-Length:", 14)) {
948
sscanf(response, "Content-Length: %d", &length);
949
} else if(dirent && dirent->metadata && !strncmp(response, "x-amz-meta-", 11)) {
950
struct amz_metadata_object *obj;
951
obj = malloc(sizeof(*obj));
952
sscanf(response, "x-amz-meta-%[^:]: %s", obj->type, obj->value);
953
list_push_tail(dirent->metadata, obj);
954
} else if(dirent && !strncmp(response, "Last-Modified:", 14)) {
957
sscanf(response, "Last-Modified: %s", date_str);
958
strptime(date_str, "%a, %d %b %Y %H:%M:%S %Z", &date);
960
dirent->last_modified = mktime(&date);
961
} else if(dirent && !strncmp(response, "ETag:", 5)) {
962
sscanf(response, "ETag: \"%[^\"]\"", dirent->digest);
965
if(!strcmp(response, "Server: AmazonS3")) break;
966
} while(link_readline(server, response, HEADER_LINE_MAX, stoptime));
968
dirent->size = length;
969
sprintf(dirent->key, "%s", remotename);
970
dirent->owner[0] = 0;
971
dirent->display_name = 0;
974
link_readline(server, response, HEADER_LINE_MAX, stoptime);
975
outfile = fopen(localname, "w");
977
//fprintf(stderr, "error opening destination file\n");
981
link_stream_to_file(server, outfile, length, stoptime);
988
int s3_rm_file(char* filename, char* bucketname, const char* access_key_id, const char* access_key) {
989
struct s3_message mesg;
991
time_t stoptime = time(0)+s3_timeout;
992
char response[HEADER_LINE_MAX];
996
if(!access_key_id || !access_key || !s3_endpoint) return -1;
998
mesg.type = S3_MESG_DELETE;
999
mesg.path = filename;
1000
mesg.bucket = bucketname;
1001
mesg.content_type = NULL;
1002
mesg.content_md5 = NULL;
1003
mesg.content_length = 0;
1004
mesg.date = time(0);
1006
mesg.amz_headers = NULL;
1008
server = link_connect(s3_address, 80, stoptime);
1009
if(!server) return -1;
1011
sign_message(&mesg, access_key_id, access_key);
1012
length = s3_message_to_string(&mesg, &text);
1014
link_putlstring(server, text, length, stoptime);
1017
link_readline(server, response, HEADER_LINE_MAX, stoptime);
1018
if(strcmp(response, "HTTP/1.1 204 No Content")) {
1019
// Error: transfer failed; close connection and return failure
1020
//fprintf(stderr, "Error: delete file failed\nResponse: %s\n", response);
1025
//fprintf(stderr, "Response:\n");
1027
// fprintf(stderr, "\t%s\n", response);
1028
if(!strcmp(response, "Server: AmazonS3")) break;
1029
} while(link_readline(server, response, HEADER_LINE_MAX, stoptime));
1035
int s3_stat_file(char* filename, char* bucketname, struct s3_dirent_object* dirent, const char* access_key_id, const char* access_key) {
1036
struct s3_message mesg;
1037
struct link* server;
1038
time_t stoptime = time(0)+s3_timeout;
1039
char response[HEADER_LINE_MAX];
1043
if(!access_key_id || !access_key || !s3_endpoint) return -1;
1045
mesg.type = S3_MESG_HEAD;
1046
mesg.path = filename;
1047
mesg.bucket = bucketname;
1048
mesg.content_type = NULL;
1049
mesg.content_md5 = NULL;
1050
mesg.content_length = 0;
1051
mesg.date = time(0);
1053
mesg.amz_headers = NULL;
1055
server = link_connect(s3_address, 80, stoptime);
1056
if(!server) return -1;
1058
sign_message(&mesg, access_key_id, access_key);
1059
length = s3_message_to_string(&mesg, &text);
1061
link_putlstring(server, text, length, stoptime);
1064
link_readline(server, response, HEADER_LINE_MAX, stoptime);
1065
if(strcmp(response, "HTTP/1.1 200 OK")) {
1066
// Error: transfer failed; close connection and return failure
1067
//fprintf(stderr, "Error: request file failed\nResponse: %s\n", response);
1073
if(!strncmp(response, "Content-Length:", 14)) {
1074
sscanf(response, "Content-Length: %d", &length);
1075
} else if(dirent->metadata && !strncmp(response, "x-amz-meta-", 11)) {
1076
struct amz_metadata_object *obj;
1077
obj = malloc(sizeof(*obj));
1078
sscanf(response, "x-amz-meta-%[^:]: %s", obj->type, obj->value);
1079
list_push_tail(dirent->metadata, obj);
1080
} else if(!strncmp(response, "Last-Modified:", 14)) {
1082
char date_str[1024];
1083
sscanf(response, "Last-Modified: %s", date_str);
1084
strptime(date_str, "%a, %d %b %Y %H:%M:%S %Z", &date);
1086
dirent->last_modified = mktime(&date);
1087
} else if(!strncmp(response, "ETag:", 5)) {
1088
sscanf(response, "ETag: \"%[^\"]\"", dirent->digest);
1091
if(!strcmp(response, "Server: AmazonS3")) break;
1092
} while(link_readline(server, response, HEADER_LINE_MAX, stoptime));
1093
dirent->size = length;
1094
sprintf(dirent->key, "%s", filename);
1095
dirent->owner[0] = 0;
1096
dirent->display_name = 0;