├── .gitignore ├── debian ├── postinst ├── changelog ├── changelog.Debian ├── control └── control.dev ├── TODO ├── README ├── mswin ├── rmrf.bat └── libs3.def ├── test ├── goodxml_01.xml ├── goodxml_02.xml ├── badxml_01.xml ├── test.sh └── goodxml_03.xml ├── ChangeLog ├── archlinux └── PKGBUILD ├── LICENSE ├── inc ├── mingw │ ├── sys │ │ ├── select.h │ │ └── utsname.h │ └── pthread.h ├── request_context.h ├── response_headers_handler.h ├── simplexml.h ├── error_parser.h ├── util.h ├── string_buffer.h └── request.h ├── src ├── mingw_s3_functions.c ├── testsimplexml.c ├── mingw_functions.c ├── simplexml.c ├── request_context.c ├── service.c ├── response_headers_handler.c ├── error_parser.c ├── acl.c ├── object.c ├── util.c └── general.c ├── libs3.spec ├── INSTALL ├── GNUmakefile.mingw ├── GNUmakefile.osx └── GNUmakefile /.gitignore: -------------------------------------------------------------------------------- 1 | build 2 | build-debug 3 | 4 | -------------------------------------------------------------------------------- /debian/postinst: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ldconfig 4 | -------------------------------------------------------------------------------- /TODO: -------------------------------------------------------------------------------- 1 | * Implement functions for generating form stuff for posting to s3 2 | 3 | * Write s3 man page 4 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | This directory contains the libs3 library. 2 | 3 | The libs3 library is free software. See the file LICENSE for copying 4 | permission. 5 | -------------------------------------------------------------------------------- /mswin/rmrf.bat: -------------------------------------------------------------------------------- 1 | @echo off 2 | 3 | if exist "%1". ( 4 | rmdir /S /Q "%1" 5 | ) 6 | 7 | if exist "%1". ( 8 | del /Q "%1" 9 | ) 10 | -------------------------------------------------------------------------------- /debian/changelog: -------------------------------------------------------------------------------- 1 | libs3 (all) unstable; urgency=low 2 | 3 | * This file is not maintained. See project source code for changes. 4 | 5 | -- Bryan Ischo Wed, 06 Aug 2008 09:36:43 -0400 6 | -------------------------------------------------------------------------------- /debian/changelog.Debian: -------------------------------------------------------------------------------- 1 | libs3 (all) unstable; urgency=low 2 | 3 | * libs3 Debian maintainer and upstream author are identical. 4 | Therefore see normal changelog file for Debian changes. 5 | 6 | -- Bryan Ischo Wed, 06 Aug 2008 09:36:43 -0400 7 | -------------------------------------------------------------------------------- /test/goodxml_01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | NoSuchKey 4 | The resource & then]]> you requested does not exist & so there 5 | /mybucket/myfoto.jpg 6 | 4442587FB7D0A2F9 7 | 8 | -------------------------------------------------------------------------------- /debian/control: -------------------------------------------------------------------------------- 1 | Package: libs3 2 | Source: THIS LINE WILL BE REMOVED, dpkg-shlibdepends NEEDS IT 3 | Version: LIBS3_VERSION 4 | Architecture: DEBIAN_ARCHITECTURE 5 | Section: net 6 | Priority: extra 7 | Maintainer: Bryan Ischo 8 | Homepage: http://libs3.ischo.com/index.html 9 | Description: C Library and Tools for Amazon S3 Access 10 | This package includes the libs3 shared object library, needed to run 11 | applications compiled against libs3, and additionally contains the s3 12 | utility for accessing Amazon S3. 13 | -------------------------------------------------------------------------------- /mswin/libs3.def: -------------------------------------------------------------------------------- 1 | EXPORTS 2 | S3_convert_acl 3 | S3_copy_object 4 | S3_create_bucket 5 | S3_create_request_context 6 | S3_deinitialize 7 | S3_delete_bucket 8 | S3_delete_object 9 | S3_destroy_request_context 10 | S3_generate_authenticated_query_string 11 | S3_get_acl 12 | S3_get_object 13 | S3_get_request_context_fdsets 14 | S3_get_server_access_logging 15 | S3_get_status_name 16 | S3_head_object 17 | S3_initialize 18 | S3_list_bucket 19 | S3_list_service 20 | S3_put_object 21 | S3_runall_request_context 22 | S3_runonce_request_context 23 | S3_set_acl 24 | S3_set_server_access_logging 25 | S3_status_is_retryable 26 | S3_test_bucket 27 | S3_validate_bucket_name 28 | -------------------------------------------------------------------------------- /ChangeLog: -------------------------------------------------------------------------------- 1 | Thu Sep 18 10:03:02 NZST 2008 bryan@ischo.com 2 | * This file is no longer maintained, sorry 3 | 4 | Sat Aug 9 13:44:21 NZST 2008 bryan@ischo.com 5 | * Fixed bug wherein keys with non-URI-safe characters did not work 6 | correctly because they were not being URI-encoded in the request UR 7 | * Split RPM and DEB packages into normal and devel packages 8 | 9 | Fri Aug 8 22:40:19 NZST 2008 bryan@ischo.com 10 | * Branched 0.4 11 | * Created RPM and Debian packaging 12 | 13 | Tue Aug 5 08:52:33 NZST 2008 bryan@ischo.com 14 | * Bumped version number to 0.3 15 | * Moved Makefile to GNUmakefile, added shared library build 16 | * Added a bunch of GNU standard files (README, INSTALL, ChangeLog, etc) 17 | -------------------------------------------------------------------------------- /archlinux/PKGBUILD: -------------------------------------------------------------------------------- 1 | # Contributor: Bryan Ischo 2 | pkgname=libs3 3 | pkgver=trunk 4 | pkgrel=1 5 | pkgdesc="C Library and Tools for Amazon S3 Access" 6 | arch=('i686' 'x86_64') 7 | url="http://libs3.ischo.com/index.html" 8 | license=('GPL') 9 | groups=() 10 | depends=('libxml2' 'openssl' 'curl') 11 | makedepends=('make' 'libxml2' 'openssl' 'curl') 12 | provides=() 13 | conflicts=() 14 | replaces=() 15 | backup=() 16 | options=() 17 | install= 18 | source=(http://libs3.ischo.com/$pkgname-$pkgver.tar.gz) 19 | noextract=() 20 | md5sums=('source md5') #generate with 'makepkg -g' 21 | 22 | build() { 23 | cd "$srcdir/$pkgname-$pkgver" 24 | 25 | DESTDIR=$pkgdir/usr make install || return 1 26 | } 27 | 28 | # vim:set ts=2 sw=2 et: 29 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | Copyright 2008 Bryan Ischo 2 | 3 | libs3 is free software: you can redistribute it and/or modify it under the 4 | terms of the GNU General Public License as published by the Free Software 5 | Foundation, version 3 of the License. 6 | 7 | In addition, as a special exception, the copyright holders give 8 | permission to link the code of this library and its programs with the 9 | OpenSSL library, and distribute linked combinations including the two. 10 | 11 | libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 12 | WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 13 | FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 14 | details. 15 | 16 | You should have received a copy of the GNU General Public License version 3 17 | along with libs3, in a file named COPYING. If not, see 18 | . 19 | 20 | 21 | -------------------------------------------------------------------------------- /debian/control.dev: -------------------------------------------------------------------------------- 1 | Package: libs3-dev 2 | Version: LIBS3_VERSION 3 | Architecture: DEBIAN_ARCHITECTURE 4 | Section: libdevel 5 | Priority: extra 6 | Depends: libs3 (>= LIBS3_VERSION) 7 | Maintainer: Bryan Ischo 8 | Homepage: http://libs3.ischo.com/index.html 9 | Description: C Development Library for Amazon S3 Access 10 | This library provides an API for using Amazon's S3 service (see 11 | http://s3.amazonaws.com). Its design goals are: 12 | . 13 | - To provide a simple and straightforward API for accessing all of S3's 14 | functionality 15 | - To not require the developer using libs3 to need to know anything about: 16 | - HTTP 17 | - XML 18 | - SSL 19 | In other words, this API is meant to stand on its own, without requiring 20 | any implicit knowledge of how S3 services are accessed using HTTP 21 | protocols. 22 | - To be usable from multithreaded code 23 | - To be usable by code which wants to process multiple S3 requests 24 | simultaneously from a single thread 25 | - To be usable in the simple, straightforward way using sequentialized 26 | blocking requests 27 | -------------------------------------------------------------------------------- /inc/mingw/sys/select.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * select.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | // This file is used only on a MingW build, and converts an include of 28 | // sys/select.h to its Windows equivalent 29 | 30 | #include 31 | -------------------------------------------------------------------------------- /src/mingw_s3_functions.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * mingw_s3_functions.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | int setenv(const char *a, const char *b, int c) 28 | { 29 | (void) c; 30 | 31 | return SetEnvironmentVariable(a, b); 32 | } 33 | 34 | int unsetenv(const char *a) 35 | { 36 | return SetEnvironmentVariable(a, 0); 37 | } 38 | -------------------------------------------------------------------------------- /inc/request_context.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * request_context.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #ifndef REQUEST_CONTEXT_H 28 | #define REQUEST_CONTEXT_H 29 | 30 | #include "libs3.h" 31 | 32 | struct S3RequestContext 33 | { 34 | CURLM *curlm; 35 | 36 | struct Request *requests; 37 | }; 38 | 39 | 40 | #endif /* REQUEST_CONTEXT_H */ 41 | -------------------------------------------------------------------------------- /inc/mingw/sys/utsname.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * utsname.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | // This file is used only on a MingW build, and provides an implementation 28 | // of POSIX sys/utsname.h 29 | 30 | #ifndef UTSNAME_H 31 | #define UTSNAME_H 32 | 33 | struct utsname 34 | { 35 | const char *sysname; 36 | const char *machine; 37 | }; 38 | 39 | int uname(struct utsname *); 40 | 41 | #endif /* UTSNAME_H */ 42 | -------------------------------------------------------------------------------- /inc/mingw/pthread.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * pthread.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #ifndef PTHREAD_H 28 | #define PTHREAD_H 29 | 30 | // This is a minimal implementation of pthreads on Windows, implementing just 31 | // the APIs needed by libs3 32 | 33 | unsigned long pthread_self(); 34 | 35 | typedef struct 36 | { 37 | CRITICAL_SECTION criticalSection; 38 | } pthread_mutex_t; 39 | 40 | int pthread_mutex_init(pthread_mutex_t *mutex, void *); 41 | int pthread_mutex_lock(pthread_mutex_t *mutex); 42 | int pthread_mutex_unlock(pthread_mutex_t *mutex); 43 | int pthread_mutex_destroy(pthread_mutex_t *mutex); 44 | 45 | #endif /* PTHREAD_H */ 46 | -------------------------------------------------------------------------------- /test/goodxml_02.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Data 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /test/badxml_01.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | 48 | 49 | 50 | 51 | 52 | 53 | 54 | Data 55 | 56 | 57 | 58 | 59 | 60 | 61 | 62 | 63 | 64 | 65 | 66 | 67 | 68 | 69 | 70 | 71 | 72 | 73 | 74 | 75 | 76 | 77 | 78 | 79 | 80 | 81 | 82 | 83 | 84 | 85 | 86 | 87 | 88 | 89 | 90 | 91 | 92 | 93 | 94 | 95 | 96 | 97 | 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | 106 | -------------------------------------------------------------------------------- /libs3.spec: -------------------------------------------------------------------------------- 1 | Summary: C Library and Tools for Amazon S3 Access 2 | Name: libs3 3 | Version: trunk 4 | Release: 1 5 | License: GPL 6 | Group: Networking/Utilities 7 | URL: http://sourceforge.net/projects/reallibs3 8 | Source0: libs3-trunk.tar.gz 9 | Buildroot: %{_tmppath}/%{name}-%{version}-%{release}-root 10 | # Want to include curl dependencies, but older Fedora Core uses curl-devel, 11 | # and newer Fedora Core uses libcurl-devel ... have to figure out how to 12 | # handle this problem, but for now, just don't check for any curl libraries 13 | # Buildrequires: curl-devel 14 | Buildrequires: libxml2-devel 15 | Buildrequires: openssl-devel 16 | Buildrequires: make 17 | # Requires: libcurl 18 | Requires: libxml2 19 | Requires: openssl 20 | 21 | %define debug_package %{nil} 22 | 23 | %description 24 | This package includes the libs3 shared object library, needed to run 25 | applications compiled against libs3, and additionally contains the s3 26 | utility for accessing Amazon S3. 27 | 28 | %package devel 29 | Summary: Headers and documentation for libs3 30 | Group: Development/Libraries 31 | Requires: %{name} = %{version}-%{release} 32 | 33 | %description devel 34 | This library provides an API for using Amazon's S3 service (see 35 | http://s3.amazonaws.com). Its design goals are: 36 | 37 | - To provide a simple and straightforward API for accessing all of S3's 38 | functionality 39 | - To not require the developer using libs3 to need to know anything about: 40 | - HTTP 41 | - XML 42 | - SSL 43 | In other words, this API is meant to stand on its own, without requiring 44 | any implicit knowledge of how S3 services are accessed using HTTP 45 | protocols. 46 | - To be usable from multithreaded code 47 | - To be usable by code which wants to process multiple S3 requests 48 | simultaneously from a single thread 49 | - To be usable in the simple, straightforward way using sequentialized 50 | blocking requests 51 | 52 | 53 | %prep 54 | %setup -q 55 | 56 | %build 57 | BUILD=$RPM_BUILD_ROOT/build make exported 58 | 59 | %install 60 | BUILD=$RPM_BUILD_ROOT/build DESTDIR=$RPM_BUILD_ROOT/usr make install 61 | rm -rf $RPM_BUILD_ROOT/build 62 | 63 | %clean 64 | rm -rf $RPM_BUILD_ROOT 65 | 66 | %files 67 | %defattr(-,root,root,-) 68 | /usr/bin/s3 69 | /usr/lib/libs3.so* 70 | 71 | %files devel 72 | %defattr(-,root,root,-) 73 | /usr/include/libs3.h 74 | /usr/lib/libs3.a 75 | 76 | %changelog 77 | * Sat Aug 09 2008 Bryan Ischo 78 | - Split into regular and devel packages. 79 | 80 | * Tue Aug 05 2008 Bryan Ischo 81 | - Initial build. 82 | -------------------------------------------------------------------------------- /inc/response_headers_handler.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * response_headers_handler.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #ifndef RESPONSE_HEADERS_HANDLER_H 28 | #define RESPONSE_HEADERS_HANDLER_H 29 | 30 | #include "libs3.h" 31 | #include "string_buffer.h" 32 | #include "util.h" 33 | 34 | 35 | typedef struct ResponseHeadersHandler 36 | { 37 | // The structure to pass to the headers callback. This is filled in by 38 | // the ResponseHeadersHandler from the headers added to it. 39 | S3ResponseProperties responseProperties; 40 | 41 | // Set to 1 after the done call has been made 42 | int done; 43 | 44 | // copied into here. We allow 128 bytes for each header, plus \0 term. 45 | string_multibuffer(responsePropertyStrings, 5 * 129); 46 | 47 | // responseproperties.metaHeaders strings get copied into here 48 | string_multibuffer(responseMetaDataStrings, 49 | COMPACTED_METADATA_BUFFER_SIZE); 50 | 51 | // Response meta data 52 | S3NameValue responseMetaData[S3_MAX_METADATA_COUNT]; 53 | } ResponseHeadersHandler; 54 | 55 | 56 | void response_headers_handler_initialize(ResponseHeadersHandler *handler); 57 | 58 | void response_headers_handler_add(ResponseHeadersHandler *handler, 59 | char *data, int dataLen); 60 | 61 | void response_headers_handler_done(ResponseHeadersHandler *handler, 62 | CURL *curl); 63 | 64 | #endif /* RESPONSE_HEADERS_HANDLER_H */ 65 | -------------------------------------------------------------------------------- /inc/simplexml.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * simplexml.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #ifndef SIMPLEXML_H 28 | #define SIMPLEXML_H 29 | 30 | #include "libs3.h" 31 | 32 | 33 | // Simple XML callback. 34 | // 35 | // elementPath: is the full "path" of the element; i.e. 36 | // data would have 'data' in the element 37 | // foo/bar/baz. 38 | // 39 | // Return of anything other than S3StatusOK causes the calling 40 | // simplexml_add() function to immediately stop and return the status. 41 | // 42 | // data is passed in as 0 on end of element 43 | typedef S3Status (SimpleXmlCallback)(const char *elementPath, const char *data, 44 | int dataLen, void *callbackData); 45 | 46 | typedef struct SimpleXml 47 | { 48 | void *xmlParser; 49 | 50 | SimpleXmlCallback *callback; 51 | 52 | void *callbackData; 53 | 54 | char elementPath[512]; 55 | 56 | int elementPathLen; 57 | 58 | S3Status status; 59 | } SimpleXml; 60 | 61 | 62 | // Simple XML parsing 63 | // ---------------------------------------------------------------------------- 64 | 65 | // Always call this, even if the simplexml doesn't end up being used 66 | void simplexml_initialize(SimpleXml *simpleXml, SimpleXmlCallback *callback, 67 | void *callbackData); 68 | 69 | S3Status simplexml_add(SimpleXml *simpleXml, const char *data, int dataLen); 70 | 71 | 72 | // Always call this 73 | void simplexml_deinitialize(SimpleXml *simpleXml); 74 | 75 | 76 | #endif /* SIMPLEXML_H */ 77 | -------------------------------------------------------------------------------- /INSTALL: -------------------------------------------------------------------------------- 1 | 2 | To install libs3 on a POSIX system (except Microsoft Windows): 3 | -------------------------------------------------------------- 4 | 5 | Note that all POSIX builds have prerequisites, such as development libraries 6 | that libs3 requires and that must be installed at the time that libs3 is 7 | built. The easiest way to find out what those are, is to run the build 8 | command and then observe the results. 9 | 10 | *** For RPM-based systems (Fedora Core, Mandrake, etc) *** 11 | 12 | * rpmbuild -ta 13 | 14 | for example: 15 | 16 | rpmbuild -ta libs3-0.3.tar.gz 17 | 18 | 19 | *** For dpkg-based systems (Debian, Ubuntu, etc) *** 20 | 21 | * make deb 22 | 23 | This will produce a Debian package in the build/pkg directory. 24 | 25 | 26 | *** For all other systems *** 27 | 28 | * make [DESTDIR=destination root] install 29 | 30 | DESTDIR defaults to /usr 31 | 32 | 33 | To install libs3 on a Microsoft Windows system: 34 | ----------------------------------------------- 35 | 36 | *** Using MingW *** 37 | 38 | * libs3 can be built on Windows using the MingW compiler. No other tool 39 | is needed. However, the following libraries are needed to build libs3: 40 | 41 | - curl development libraries 42 | - libxml2 development libraries, and the libraries that it requires: 43 | - iconv 44 | - zlib 45 | 46 | These projects are independent of libs3, and their release schedule and 47 | means of distribution would make it very difficult to provide links to 48 | the files to download and keep them up-to-date in this file, so no attempt 49 | is made here. 50 | 51 | Development libraries and other files can be placed in: 52 | c:\libs3-libs\bin 53 | c:\libs3-libs\include 54 | 55 | If the above locations are used, then the GNUmakefile.mingw will work with 56 | no special caveats. If the above locations are not used, then the following 57 | environment variables should be set: 58 | CURL_LIBS should be set to the MingW compiler flags needed to locate and 59 | link in the curl libraries 60 | CURL_CFLAGS should be set to the MingW compiler flags needed to locate and 61 | include the curl headers 62 | LIBXML2_LIBS should be set to the MingW compiler flags needed to locate and 63 | link in the libxml2 libraries 64 | LIBXML2_CFLAGS should be set to the MingW compiler flags needed to locate and 65 | include the libxml2 headers 66 | 67 | * mingw32-make [DESTDIR=destination] -f GNUmakefile.mingw install 68 | 69 | DESTDIR defaults to libs3- 70 | 71 | * DESTDIR can be zipped up into a .zip file for distribution. For best 72 | results, the dependent libraries (curl, openssl, etc) should be included, 73 | along with their licenses. 74 | -------------------------------------------------------------------------------- /src/testsimplexml.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * testsimplexml.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "simplexml.h" 32 | 33 | static S3Status simpleXmlCallback(const char *elementPath, const char *data, 34 | int dataLen, void *callbackData) 35 | { 36 | (void) callbackData; 37 | 38 | printf("[%s]: [%.*s]\n", elementPath, dataLen, data); 39 | 40 | return S3StatusOK; 41 | } 42 | 43 | 44 | // The only argument allowed is a specification of the random seed to use 45 | int main(int argc, char **argv) 46 | { 47 | if (argc > 1) { 48 | char *arg = argv[1]; 49 | int seed = 0; 50 | while (*arg) { 51 | seed *= 10; 52 | seed += (*arg++ - '0'); 53 | } 54 | 55 | srand(seed); 56 | } 57 | else { 58 | srand(time(0)); 59 | } 60 | 61 | SimpleXml simpleXml; 62 | 63 | simplexml_initialize(&simpleXml, &simpleXmlCallback, 0); 64 | 65 | // Read chunks of 10K from stdin, and then feed them in random chunks 66 | // to simplexml_add 67 | char inbuf[10000]; 68 | 69 | int amt_read; 70 | while ((amt_read = fread(inbuf, 1, sizeof(inbuf), stdin)) > 0) { 71 | char *buf = inbuf; 72 | while (amt_read) { 73 | int amt = (rand() % amt_read) + 1; 74 | S3Status status = simplexml_add(&simpleXml, buf, amt); 75 | if (status != S3StatusOK) { 76 | fprintf(stderr, "ERROR: Parse failure: %d\n", status); 77 | simplexml_deinitialize(&simpleXml); 78 | return -1; 79 | } 80 | buf += amt, amt_read -= amt; 81 | } 82 | } 83 | 84 | simplexml_deinitialize(&simpleXml); 85 | 86 | return 0; 87 | } 88 | -------------------------------------------------------------------------------- /inc/error_parser.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * error_parser.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #ifndef ERROR_PARSER_H 28 | #define ERROR_PARSER_H 29 | 30 | #include "libs3.h" 31 | #include "simplexml.h" 32 | #include "string_buffer.h" 33 | 34 | 35 | #define EXTRA_DETAILS_SIZE 8 36 | 37 | typedef struct ErrorParser 38 | { 39 | // This is the S3ErrorDetails that this ErrorParser fills in from the 40 | // data that it parses 41 | S3ErrorDetails s3ErrorDetails; 42 | 43 | // This is the error XML parser 44 | SimpleXml errorXmlParser; 45 | 46 | // Set to 1 after the first call to add 47 | int errorXmlParserInitialized; 48 | 49 | // Used to buffer the S3 Error Code as it is read in 50 | string_buffer(code, 1024); 51 | 52 | // Used to buffer the S3 Error Message as it is read in 53 | string_buffer(message, 1024); 54 | 55 | // Used to buffer the S3 Error Resource as it is read in 56 | string_buffer(resource, 1024); 57 | 58 | // Used to buffer the S3 Error Further Details as it is read in 59 | string_buffer(furtherDetails, 1024); 60 | 61 | // The extra details; we support up to EXTRA_DETAILS_SIZE of them 62 | S3NameValue extraDetails[EXTRA_DETAILS_SIZE]; 63 | 64 | // This is the buffer from which the names and values used in extraDetails 65 | // are allocated 66 | string_multibuffer(extraDetailsNamesValues, EXTRA_DETAILS_SIZE * 1024); 67 | } ErrorParser; 68 | 69 | 70 | // Always call this 71 | void error_parser_initialize(ErrorParser *errorParser); 72 | 73 | S3Status error_parser_add(ErrorParser *errorParser, char *buffer, 74 | int bufferSize); 75 | 76 | void error_parser_convert_status(ErrorParser *errorParser, S3Status *status); 77 | 78 | // Always call this 79 | void error_parser_deinitialize(ErrorParser *errorParser); 80 | 81 | 82 | #endif /* ERROR_PARSER_H */ 83 | -------------------------------------------------------------------------------- /src/mingw_functions.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * mingw_functions.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | 30 | unsigned long pthread_self() 31 | { 32 | return (unsigned long) GetCurrentThreadId(); 33 | } 34 | 35 | 36 | int pthread_mutex_init(pthread_mutex_t *mutex, void *v) 37 | { 38 | (void) v; 39 | 40 | InitializeCriticalSection(&(mutex->criticalSection)); 41 | 42 | return 0; 43 | } 44 | 45 | 46 | int pthread_mutex_lock(pthread_mutex_t *mutex) 47 | { 48 | EnterCriticalSection(&(mutex->criticalSection)); 49 | 50 | return 0; 51 | } 52 | 53 | 54 | int pthread_mutex_unlock(pthread_mutex_t *mutex) 55 | { 56 | LeaveCriticalSection(&(mutex->criticalSection)); 57 | 58 | return 0; 59 | } 60 | 61 | 62 | int pthread_mutex_destroy(pthread_mutex_t *mutex) 63 | { 64 | DeleteCriticalSection(&(mutex->criticalSection)); 65 | 66 | return 0; 67 | } 68 | 69 | 70 | int uname(struct utsname *u) 71 | { 72 | OSVERSIONINFO info; 73 | info.dwOSVersionInfoSize = sizeof(info); 74 | 75 | if (!GetVersionEx(&info)) { 76 | return -1; 77 | } 78 | 79 | u->machine = ""; 80 | 81 | switch (info.dwMajorVersion) { 82 | case 4: 83 | switch (info.dwMinorVersion) { 84 | case 0: 85 | u->sysname = "Microsoft Windows NT 4.0"; 86 | break; 87 | case 10: 88 | u->sysname = "Microsoft Windows 98"; 89 | break; 90 | case 90: 91 | u->sysname = "Microsoft Windows Me"; 92 | break; 93 | default: 94 | return -1; 95 | } 96 | break; 97 | 98 | case 5: 99 | switch (info.dwMinorVersion) { 100 | case 0: 101 | u->sysname = "Microsoft Windows 2000"; 102 | break; 103 | case 1: 104 | u->sysname = "Microsoft Windows XP"; 105 | break; 106 | case 2: 107 | u->sysname = "Microsoft Server 2003"; 108 | break; 109 | default: 110 | return -1; 111 | } 112 | break; 113 | 114 | default: 115 | return -1; 116 | } 117 | 118 | return 0; 119 | } 120 | -------------------------------------------------------------------------------- /inc/util.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * util.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #ifndef UTIL_H 28 | #define UTIL_H 29 | 30 | #include 31 | #include 32 | #include 33 | #include "libs3.h" 34 | 35 | // acl groups 36 | #define ACS_URL "http://acs.amazonaws.com/groups/" 37 | 38 | #define ACS_GROUP_ALL_USERS ACS_URL "global/AllUsers" 39 | #define ACS_GROUP_AWS_USERS ACS_URL "global/AuthenticatedUsers" 40 | #define ACS_GROUP_LOG_DELIVERY ACS_URL "s3/LogDelivery" 41 | 42 | 43 | 44 | // Derived from S3 documentation 45 | 46 | // This is the maximum number of bytes needed in a "compacted meta header" 47 | // buffer, which is a buffer storing all of the compacted meta headers. 48 | #define COMPACTED_METADATA_BUFFER_SIZE \ 49 | (S3_MAX_METADATA_COUNT * sizeof(S3_METADATA_HEADER_NAME_PREFIX "n: v")) 50 | 51 | // Maximum url encoded key size; since every single character could require 52 | // URL encoding, it's 3 times the size of a key (since each url encoded 53 | // character takes 3 characters: %NN) 54 | #define MAX_URLENCODED_KEY_SIZE (3 * S3_MAX_KEY_SIZE) 55 | 56 | // This is the maximum size of a URI that could be passed to S3: 57 | // https://s3.amazonaws.com/${BUCKET}/${KEY}?acl 58 | // 255 is the maximum bucket length 59 | #define MAX_URI_SIZE \ 60 | ((sizeof("https:///") - 1) + S3_MAX_HOSTNAME_SIZE + 255 + 1 + \ 61 | MAX_URLENCODED_KEY_SIZE + (sizeof("?torrent") - 1) + 1) 62 | 63 | // Maximum size of a canonicalized resource 64 | #define MAX_CANONICALIZED_RESOURCE_SIZE \ 65 | (1 + 255 + 1 + MAX_URLENCODED_KEY_SIZE + (sizeof("?torrent") - 1) + 1) 66 | 67 | 68 | // Utilities ----------------------------------------------------------------- 69 | 70 | // URL-encodes a string from [src] into [dest]. [dest] must have at least 71 | // 3x the number of characters that [source] has. At most [maxSrcSize] bytes 72 | // from [src] are encoded; if more are present in [src], 0 is returned from 73 | // urlEncode, else nonzero is returned. 74 | int urlEncode(char *dest, const char *src, int maxSrcSize); 75 | 76 | // Returns < 0 on failure >= 0 on success 77 | int64_t parseIso8601Time(const char *str); 78 | 79 | uint64_t parseUnsignedInt(const char *str); 80 | 81 | // base64 encode bytes. The output buffer must have at least 82 | // ((4 * (inLen + 1)) / 3) bytes in it. Returns the number of bytes written 83 | // to [out]. 84 | int base64Encode(const unsigned char *in, int inLen, char *out); 85 | 86 | // Compute HMAC-SHA-1 with key [key] and message [message], storing result 87 | // in [hmac] 88 | void HMAC_SHA1(unsigned char hmac[20], const unsigned char *key, int key_len, 89 | const unsigned char *message, int message_len); 90 | 91 | // Compute a 64-bit hash values given a set of bytes 92 | uint64_t hash(const unsigned char *k, int length); 93 | 94 | // Because Windows seems to be missing isblank(), use our own; it's a very 95 | // easy function to write in any case 96 | int is_blank(char c); 97 | 98 | #endif /* UTIL_H */ 99 | -------------------------------------------------------------------------------- /inc/string_buffer.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * string_buffer.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #ifndef STRING_BUFFER_H 28 | #define STRING_BUFFER_H 29 | 30 | #include 31 | 32 | 33 | // Declare a string_buffer with the given name of the given maximum length 34 | #define string_buffer(name, len) \ 35 | char name[len + 1]; \ 36 | int name##Len 37 | 38 | 39 | // Initialize a string_buffer 40 | #define string_buffer_initialize(sb) \ 41 | do { \ 42 | sb[0] = 0; \ 43 | sb##Len = 0; \ 44 | } while (0) 45 | 46 | 47 | // Append [len] bytes of [str] to [sb], setting [all_fit] to 1 if it fit, and 48 | // 0 if it did not 49 | #define string_buffer_append(sb, str, len, all_fit) \ 50 | do { \ 51 | sb##Len += snprintf(&(sb[sb##Len]), sizeof(sb) - sb##Len - 1, \ 52 | "%.*s", (int) (len), str); \ 53 | if (sb##Len > (int) (sizeof(sb) - 1)) { \ 54 | sb##Len = sizeof(sb) - 1; \ 55 | all_fit = 0; \ 56 | } \ 57 | else { \ 58 | all_fit = 1; \ 59 | } \ 60 | } while (0) 61 | 62 | 63 | // Declare a string multibuffer with the given name of the given maximum size 64 | #define string_multibuffer(name, size) \ 65 | char name[size]; \ 66 | int name##Size 67 | 68 | 69 | // Initialize a string_multibuffer 70 | #define string_multibuffer_initialize(smb) \ 71 | do { \ 72 | smb##Size = 0; \ 73 | } while (0) 74 | 75 | 76 | // Evaluates to the current string within the string_multibuffer 77 | #define string_multibuffer_current(smb) \ 78 | &(smb[smb##Size]) 79 | 80 | 81 | // Adds a new string to the string_multibuffer 82 | #define string_multibuffer_add(smb, str, len, all_fit) \ 83 | do { \ 84 | smb##Size += (snprintf(&(smb[smb##Size]), \ 85 | sizeof(smb) - smb##Size, \ 86 | "%.*s", (int) (len), str) + 1); \ 87 | if (smb##Size > (int) sizeof(smb)) { \ 88 | smb##Size = sizeof(smb); \ 89 | all_fit = 0; \ 90 | } \ 91 | else { \ 92 | all_fit = 1; \ 93 | } \ 94 | } while (0) 95 | 96 | 97 | // Appends to the current string in the string_multibuffer. There must be a 98 | // current string, meaning that string_multibuffer_add must have been called 99 | // at least once for this string_multibuffer. 100 | #define string_multibuffer_append(smb, str, len, all_fit) \ 101 | do { \ 102 | smb##Size--; \ 103 | string_multibuffer_add(smb, str, len, all_fit); \ 104 | } while (0) 105 | 106 | 107 | #endif /* STRING_BUFFER_H */ 108 | -------------------------------------------------------------------------------- /test/test.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | # Environment: 4 | # S3_ACCESS_KEY_ID - must be set to S3 Access Key ID 5 | # S3_SECRET_ACCESS_KEY - must be set to S3 Secret Access Key 6 | # TEST_BUCKET_PREFIX - must be set to the test bucket prefix to use 7 | # S3_COMMAND - may be set to s3 command to use (i.e. valgrind s3); defaults 8 | # to "s3" 9 | 10 | if [ -z "$S3_ACCESS_KEY_ID" ]; then 11 | echo "S3_ACCESS_KEY_ID required" 12 | exit -1; 13 | fi 14 | 15 | if [ -z "$S3_SECRET_ACCESS_KEY" ]; then 16 | echo "S3_SECRET_ACCESS_KEY required" 17 | exit -1; 18 | fi 19 | 20 | if [ -z "$TEST_BUCKET_PREFIX" ]; then 21 | echo "TEST_BUCKET_PREFIX required" 22 | exit -1; 23 | fi 24 | 25 | if [ -z "$S3_COMMAND" ]; then 26 | S3_COMMAND=s3 27 | fi 28 | 29 | TEST_BUCKET=${TEST_BUCKET_PREFIX}.testbucket 30 | 31 | # Create the test bucket in EU 32 | echo "$S3_COMMAND create $TEST_BUCKET locationConstraint=EU" 33 | $S3_COMMAND create $TEST_BUCKET 34 | 35 | # List to find it 36 | echo "$S3_COMMAND list | grep $TEST_BUCKET" 37 | $S3_COMMAND list | grep $TEST_BUCKET 38 | 39 | # Test it 40 | echo "$S3_COMMAND test $TEST_BUCKET" 41 | $S3_COMMAND test $TEST_BUCKET 42 | 43 | # List to ensure that it is empty 44 | echo "$S3_COMMAND list $TEST_BUCKET" 45 | $S3_COMMAND list $TEST_BUCKET 46 | 47 | # Put some data 48 | rm -f seqdata 49 | seq 1 10000 > seqdata 50 | echo "$S3_COMMAND put $TEST_BUCKET/testkey filename=seqdata noStatus=1" 51 | $S3_COMMAND put $TEST_BUCKET/testkey filename=seqdata noStatus=1 52 | 53 | rm -f testkey 54 | # Get the data and make sure that it matches 55 | echo "$S3_COMMAND get $TEST_BUCKET/testkey filename=testkey" 56 | $S3_COMMAND get $TEST_BUCKET/testkey filename=testkey 57 | diff seqdata testkey 58 | rm -f seqdata testkey 59 | 60 | # Delete the file 61 | echo "$S3_COMMAND delete $TEST_BUCKET/testkey" 62 | $S3_COMMAND delete $TEST_BUCKET/testkey 63 | 64 | # Remove the test bucket 65 | echo "$S3_COMMAND delete $TEST_BUCKET" 66 | $S3_COMMAND delete $TEST_BUCKET 67 | 68 | # Make sure it's not there 69 | echo "$S3_COMMAND list | grep $TEST_BUCKET" 70 | $S3_COMMAND list | grep $TEST_BUCKET 71 | 72 | # Now create it again 73 | echo "$S3_COMMAND create $TEST_BUCKET" 74 | $S3_COMMAND create $TEST_BUCKET 75 | 76 | # Put 10 files in it 77 | for i in `seq 0 9`; do 78 | echo "echo \"Hello\" | $S3_COMMAND put $TEST_BUCKET/key_$i" 79 | echo "Hello" | $S3_COMMAND put $TEST_BUCKET/key_$i 80 | done 81 | 82 | # List with all details 83 | echo "$S3_COMMAND list $TEST_BUCKET allDetails=1" 84 | $S3_COMMAND list $TEST_BUCKET allDetails=1 85 | 86 | COPY_BUCKET=${TEST_BUCKET_PREFIX}.copybucket 87 | 88 | # Create another test bucket and copy a file into it 89 | echo "$S3_COMMAND create $COPY_BUCKET" 90 | $S3_COMMAND create $COPY_BUCKET 91 | echo <> acl 132 | Group Authenticated AWS Users READ 133 | EOF 134 | echo <> acl 135 | Group All Users READ_ACP 136 | EOF 137 | echo "$S3_COMMAND setacl $TEST_BUCKET filename=acl" 138 | $S3_COMMAND setacl $TEST_BUCKET filename=acl 139 | 140 | # Test to make sure that it worked 141 | rm -f acl_new 142 | echo "$S3_COMMAND getacl $TEST_BUCKET filename=acl_new allDetails=1" 143 | $S3_COMMAND getacl $TEST_BUCKET filename=acl_new allDetails=1 144 | diff acl acl_new 145 | rm -f acl acl_new 146 | 147 | # Get the key acl 148 | rm -f acl 149 | echo "$S3_COMMAND getacl $TEST_BUCKET/aclkey filename=acl allDetails=1" 150 | $S3_COMMAND getacl $TEST_BUCKET/aclkey filename=acl allDetails=1 151 | 152 | # Add READ for all AWS users, and READ_ACP for everyone 153 | echo <> acl 154 | Group Authenticated AWS Users READ 155 | EOF 156 | echo <> acl 157 | Group All Users READ_ACP 158 | EOF 159 | echo "$S3_COMMAND setacl $TEST_BUCKET/aclkey filename=acl" 160 | $S3_COMMAND setacl $TEST_BUCKET/aclkey filename=acl 161 | 162 | # Test to make sure that it worked 163 | rm -f acl_new 164 | echo "$S3_COMMAND getacl $TEST_BUCKET/aclkey filename=acl_new allDetails=1" 165 | $S3_COMMAND getacl $TEST_BUCKET/aclkey filename=acl_new allDetails=1 166 | diff acl acl_new 167 | rm -f acl acl_new 168 | 169 | # Remove the test file 170 | echo "$S3_COMMAND delete $TEST_BUCKET/aclkey" 171 | $S3_COMMAND delete $TEST_BUCKET/aclkey 172 | echo "$S3_COMMAND delete $TEST_BUCKET" 173 | $S3_COMMAND delete $TEST_BUCKET 174 | -------------------------------------------------------------------------------- /inc/request.h: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * request.h 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #ifndef REQUEST_H 28 | #define REQUEST_H 29 | 30 | #include "libs3.h" 31 | #include "error_parser.h" 32 | #include "response_headers_handler.h" 33 | #include "util.h" 34 | 35 | // Describes a type of HTTP request (these are our supported HTTP "verbs") 36 | typedef enum 37 | { 38 | HttpRequestTypeGET, 39 | HttpRequestTypeHEAD, 40 | HttpRequestTypePUT, 41 | HttpRequestTypeCOPY, 42 | HttpRequestTypeDELETE 43 | } HttpRequestType; 44 | 45 | 46 | // This completely describes a request. A RequestParams is not required to be 47 | // allocated from the heap and its lifetime is not assumed to extend beyond 48 | // the lifetime of the function to which it has been passed. 49 | typedef struct RequestParams 50 | { 51 | // Request type, affects the HTTP verb used 52 | HttpRequestType httpRequestType; 53 | 54 | // Bucket context for request 55 | S3BucketContext bucketContext; 56 | 57 | // Key, if any 58 | const char *key; 59 | 60 | // Query params - ready to append to URI (i.e. ?p1=v1?p2=v2) 61 | const char *queryParams; 62 | 63 | // sub resource, like ?acl, ?location, ?torrent, ?logging 64 | const char *subResource; 65 | 66 | // If this is a copy operation, this gives the source bucket 67 | const char *copySourceBucketName; 68 | 69 | // If this is a copy operation, this gives the source key 70 | const char *copySourceKey; 71 | 72 | // Get conditions 73 | const S3GetConditions *getConditions; 74 | 75 | // Start byte 76 | uint64_t startByte; 77 | 78 | // Byte count 79 | uint64_t byteCount; 80 | 81 | // Put properties 82 | const S3PutProperties *putProperties; 83 | 84 | // Callback to be made when headers are available. Might not be called. 85 | S3ResponsePropertiesCallback *propertiesCallback; 86 | 87 | // Callback to be made to supply data to send to S3. Might not be called. 88 | S3PutObjectDataCallback *toS3Callback; 89 | 90 | // Number of bytes total that readCallback will supply 91 | int64_t toS3CallbackTotalSize; 92 | 93 | // Callback to be made that supplies data read from S3. 94 | // Might not be called. 95 | S3GetObjectDataCallback *fromS3Callback; 96 | 97 | // Callback to be made when request is complete. This will *always* be 98 | // called. 99 | S3ResponseCompleteCallback *completeCallback; 100 | 101 | // Data passed to the callbacks 102 | void *callbackData; 103 | } RequestParams; 104 | 105 | 106 | // This is the stuff associated with a request that needs to be on the heap 107 | // (and thus live while a curl_multi is in use). 108 | typedef struct Request 109 | { 110 | // These put the request on a doubly-linked list of requests in a 111 | // request context, *if* the request is in a request context (else these 112 | // will both be 0) 113 | struct Request *prev, *next; 114 | 115 | // The status of this Request, as will be reported to the user via the 116 | // complete callback 117 | S3Status status; 118 | 119 | // The HTTP code returned by the S3 server, if it is known. Would rather 120 | // not have to keep track of this but S3 doesn't always indicate its 121 | // errors the same way 122 | int httpResponseCode; 123 | 124 | // The HTTP headers to use for the curl request 125 | struct curl_slist *headers; 126 | 127 | // The CURL structure driving the request 128 | CURL *curl; 129 | 130 | // libcurl requires that the uri be stored outside of the curl handle 131 | char uri[MAX_URI_SIZE + 1]; 132 | 133 | // Callback to be made when headers are available. Might not be called. 134 | S3ResponsePropertiesCallback *propertiesCallback; 135 | 136 | // Callback to be made to supply data to send to S3. Might not be called. 137 | S3PutObjectDataCallback *toS3Callback; 138 | 139 | // Number of bytes total that readCallback has left to supply 140 | int64_t toS3CallbackBytesRemaining; 141 | 142 | // Callback to be made that supplies data read from S3. 143 | // Might not be called. 144 | S3GetObjectDataCallback *fromS3Callback; 145 | 146 | // Callback to be made when request is complete. This will *always* be 147 | // called. 148 | S3ResponseCompleteCallback *completeCallback; 149 | 150 | // Data passed to the callbacks 151 | void *callbackData; 152 | 153 | // Handler of response headers 154 | ResponseHeadersHandler responseHeadersHandler; 155 | 156 | // This is set to nonzero after the properties callback has been made 157 | int propertiesCallbackMade; 158 | 159 | // Parser of errors 160 | ErrorParser errorParser; 161 | } Request; 162 | 163 | 164 | // Request functions 165 | // ---------------------------------------------------------------------------- 166 | 167 | // Initialize the API 168 | S3Status request_api_initialize(const char *userAgentInfo, int flags, 169 | const char *hostName); 170 | 171 | // Deinitialize the API 172 | void request_api_deinitialize(); 173 | 174 | // Perform a request; if context is 0, performs the request immediately; 175 | // otherwise, sets it up to be performed by context. 176 | void request_perform(const RequestParams *params, S3RequestContext *context); 177 | 178 | // Called by the internal request code or internal request context code when a 179 | // curl has finished the request 180 | void request_finish(Request *request); 181 | 182 | // Convert a CURLE code to an S3Status 183 | S3Status request_curl_code_to_status(CURLcode code); 184 | 185 | 186 | #endif /* REQUEST_H */ 187 | -------------------------------------------------------------------------------- /src/simplexml.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * simplexml.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | #include "simplexml.h" 30 | 31 | // Use libxml2 for parsing XML. XML is severely overused in modern 32 | // computing. It is useful for only a very small subset of tasks, but 33 | // software developers who don't know better and are afraid to go against the 34 | // grain use it for everything, and in most cases, it is completely 35 | // inappropriate. Usually, the document structure is severely under-specified 36 | // as well, as is the case with S3. We do our best by just caring about the 37 | // most important aspects of the S3 "XML document" responses: the elements and 38 | // their values. The SAX API (just about the lamest API ever devised and 39 | // proof that XML sucks - well, the real proof is how crappy all of the XML 40 | // parsing libraries are, including libxml2 - but I digress) is used here 41 | // because we don't need much from the parser and SAX is fast and low memory. 42 | // 43 | // Note that for simplicity we assume all ASCII here. No attempts are made to 44 | // detect non-ASCII sequences in utf-8 and convert them into ASCII in any way. 45 | // S3 appears to only use ASCII anyway. 46 | 47 | 48 | static xmlEntityPtr saxGetEntity(void *user_data, const xmlChar *name) 49 | { 50 | (void) user_data; 51 | 52 | return xmlGetPredefinedEntity(name); 53 | } 54 | 55 | 56 | static void saxStartElement(void *user_data, const xmlChar *nameUtf8, 57 | const xmlChar **attr) 58 | { 59 | (void) attr; 60 | 61 | SimpleXml *simpleXml = (SimpleXml *) user_data; 62 | 63 | if (simpleXml->status != S3StatusOK) { 64 | return; 65 | } 66 | 67 | // Assume that name has no non-ASCII in it 68 | char *name = (char *) nameUtf8; 69 | 70 | // Append the element to the element path 71 | int len = strlen(name); 72 | 73 | if ((simpleXml->elementPathLen + len + 1) >= 74 | (int) sizeof(simpleXml->elementPath)) { 75 | // Cannot handle this element, stop! 76 | simpleXml->status = S3StatusXmlParseFailure; 77 | return; 78 | } 79 | 80 | if (simpleXml->elementPathLen) { 81 | simpleXml->elementPath[simpleXml->elementPathLen++] = '/'; 82 | } 83 | strcpy(&(simpleXml->elementPath[simpleXml->elementPathLen]), name); 84 | simpleXml->elementPathLen += len; 85 | } 86 | 87 | 88 | static void saxEndElement(void *user_data, const xmlChar *name) 89 | { 90 | (void) name; 91 | 92 | SimpleXml *simpleXml = (SimpleXml *) user_data; 93 | 94 | if (simpleXml->status != S3StatusOK) { 95 | return; 96 | } 97 | 98 | // Call back with 0 data 99 | simpleXml->status = (*(simpleXml->callback)) 100 | (simpleXml->elementPath, 0, 0, simpleXml->callbackData); 101 | 102 | while ((simpleXml->elementPathLen > 0) && 103 | (simpleXml->elementPath[simpleXml->elementPathLen] != '/')) { 104 | simpleXml->elementPathLen--; 105 | } 106 | 107 | simpleXml->elementPath[simpleXml->elementPathLen] = 0; 108 | } 109 | 110 | 111 | static void saxCharacters(void *user_data, const xmlChar *ch, int len) 112 | { 113 | SimpleXml *simpleXml = (SimpleXml *) user_data; 114 | 115 | if (simpleXml->status != S3StatusOK) { 116 | return; 117 | } 118 | 119 | simpleXml->status = (*(simpleXml->callback)) 120 | (simpleXml->elementPath, (char *) ch, len, simpleXml->callbackData); 121 | } 122 | 123 | 124 | static void saxError(void *user_data, const char *msg, ...) 125 | { 126 | (void) msg; 127 | 128 | SimpleXml *simpleXml = (SimpleXml *) user_data; 129 | 130 | if (simpleXml->status != S3StatusOK) { 131 | return; 132 | } 133 | 134 | simpleXml->status = S3StatusXmlParseFailure; 135 | } 136 | 137 | 138 | static struct _xmlSAXHandler saxHandlerG = 139 | { 140 | 0, // internalSubsetSAXFunc 141 | 0, // isStandaloneSAXFunc 142 | 0, // hasInternalSubsetSAXFunc 143 | 0, // hasExternalSubsetSAXFunc 144 | 0, // resolveEntitySAXFunc 145 | &saxGetEntity, // getEntitySAXFunc 146 | 0, // entityDeclSAXFunc 147 | 0, // notationDeclSAXFunc 148 | 0, // attributeDeclSAXFunc 149 | 0, // elementDeclSAXFunc 150 | 0, // unparsedEntityDeclSAXFunc 151 | 0, // setDocumentLocatorSAXFunc 152 | 0, // startDocumentSAXFunc 153 | 0, // endDocumentSAXFunc 154 | &saxStartElement, // startElementSAXFunc 155 | &saxEndElement, // endElementSAXFunc 156 | 0, // referenceSAXFunc 157 | &saxCharacters, // charactersSAXFunc 158 | 0, // ignorableWhitespaceSAXFunc 159 | 0, // processingInstructionSAXFunc 160 | 0, // commentSAXFunc 161 | 0, // warningSAXFunc 162 | &saxError, // errorSAXFunc 163 | &saxError, // fatalErrorSAXFunc 164 | 0, // getParameterEntitySAXFunc 165 | &saxCharacters, // cdataBlockSAXFunc 166 | 0, // externalSubsetSAXFunc 167 | 0, // initialized 168 | 0, // _private 169 | 0, // startElementNsSAX2Func 170 | 0, // endElementNsSAX2Func 171 | 0 // xmlStructuredErrorFunc serror; 172 | }; 173 | 174 | void simplexml_initialize(SimpleXml *simpleXml, 175 | SimpleXmlCallback *callback, void *callbackData) 176 | { 177 | simpleXml->callback = callback; 178 | simpleXml->callbackData = callbackData; 179 | simpleXml->elementPathLen = 0; 180 | simpleXml->status = S3StatusOK; 181 | simpleXml->xmlParser = 0; 182 | } 183 | 184 | 185 | void simplexml_deinitialize(SimpleXml *simpleXml) 186 | { 187 | if (simpleXml->xmlParser) { 188 | xmlFreeParserCtxt(simpleXml->xmlParser); 189 | } 190 | } 191 | 192 | 193 | S3Status simplexml_add(SimpleXml *simpleXml, const char *data, int dataLen) 194 | { 195 | if (!simpleXml->xmlParser && 196 | (!(simpleXml->xmlParser = xmlCreatePushParserCtxt 197 | (&saxHandlerG, simpleXml, 0, 0, 0)))) { 198 | return S3StatusInternalError; 199 | } 200 | 201 | if (xmlParseChunk((xmlParserCtxtPtr) simpleXml->xmlParser, 202 | data, dataLen, 0)) { 203 | return S3StatusXmlParseFailure; 204 | } 205 | 206 | return simpleXml->status; 207 | } 208 | -------------------------------------------------------------------------------- /src/request_context.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * request_context.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | #include 30 | #include "request.h" 31 | #include "request_context.h" 32 | 33 | 34 | S3Status S3_create_request_context(S3RequestContext **requestContextReturn) 35 | { 36 | *requestContextReturn = 37 | (S3RequestContext *) malloc(sizeof(S3RequestContext)); 38 | 39 | if (!*requestContextReturn) { 40 | return S3StatusOutOfMemory; 41 | } 42 | 43 | if (!((*requestContextReturn)->curlm = curl_multi_init())) { 44 | free(*requestContextReturn); 45 | return S3StatusOutOfMemory; 46 | } 47 | 48 | (*requestContextReturn)->requests = 0; 49 | 50 | return S3StatusOK; 51 | } 52 | 53 | 54 | void S3_destroy_request_context(S3RequestContext *requestContext) 55 | { 56 | curl_multi_cleanup(requestContext->curlm); 57 | 58 | // For each request in the context, call back its done method with 59 | // 'interrupted' status 60 | Request *r = requestContext->requests, *rFirst = r; 61 | 62 | if (r) do { 63 | r->status = S3StatusInterrupted; 64 | Request *rNext = r->next; 65 | request_finish(r); 66 | r = rNext; 67 | } while (r != rFirst); 68 | 69 | free(requestContext); 70 | } 71 | 72 | 73 | S3Status S3_runall_request_context(S3RequestContext *requestContext) 74 | { 75 | int requestsRemaining; 76 | do { 77 | fd_set readfds, writefds, exceptfds; 78 | FD_ZERO(&readfds); 79 | FD_ZERO(&writefds); 80 | FD_ZERO(&exceptfds); 81 | int maxfd; 82 | S3Status status = S3_get_request_context_fdsets 83 | (requestContext, &readfds, &writefds, &exceptfds, &maxfd); 84 | if (status != S3StatusOK) { 85 | return status; 86 | } 87 | // curl will return -1 if it hasn't even created any fds yet because 88 | // none of the connections have started yet. In this case, don't 89 | // do the select at all, because it will wait forever; instead, just 90 | // skip it and go straight to running the underlying CURL handles 91 | if (maxfd != -1) { 92 | int64_t timeout = S3_get_request_context_timeout(requestContext); 93 | struct timeval tv = { timeout / 1000, (timeout % 1000) * 1000 }; 94 | select(maxfd + 1, &readfds, &writefds, &exceptfds, 95 | (timeout == -1) ? 0 : &tv); 96 | } 97 | status = S3_runonce_request_context(requestContext, 98 | &requestsRemaining); 99 | if (status != S3StatusOK) { 100 | return status; 101 | } 102 | } while (requestsRemaining); 103 | 104 | return S3StatusOK; 105 | } 106 | 107 | 108 | S3Status S3_runonce_request_context(S3RequestContext *requestContext, 109 | int *requestsRemainingReturn) 110 | { 111 | CURLMcode status; 112 | 113 | do { 114 | status = curl_multi_perform(requestContext->curlm, 115 | requestsRemainingReturn); 116 | 117 | switch (status) { 118 | case CURLM_OK: 119 | case CURLM_CALL_MULTI_PERFORM: 120 | break; 121 | case CURLM_OUT_OF_MEMORY: 122 | return S3StatusOutOfMemory; 123 | default: 124 | return S3StatusInternalError; 125 | } 126 | 127 | CURLMsg *msg; 128 | int junk; 129 | while ((msg = curl_multi_info_read(requestContext->curlm, &junk))) { 130 | if (msg->msg != CURLMSG_DONE) { 131 | return S3StatusInternalError; 132 | } 133 | Request *request; 134 | if (curl_easy_getinfo(msg->easy_handle, CURLINFO_PRIVATE, 135 | (char **) (char *) &request) != CURLE_OK) { 136 | return S3StatusInternalError; 137 | } 138 | // Remove the request from the list of requests 139 | if (request->prev == request->next) { 140 | // It was the only one on the list 141 | requestContext->requests = 0; 142 | } 143 | else { 144 | // It doesn't matter what the order of them are, so just in 145 | // case request was at the head of the list, put the one after 146 | // request to the head of the list 147 | requestContext->requests = request->next; 148 | request->prev->next = request->next; 149 | request->next->prev = request->prev; 150 | } 151 | if ((msg->data.result != CURLE_OK) && 152 | (request->status == S3StatusOK)) { 153 | request->status = request_curl_code_to_status 154 | (msg->data.result); 155 | } 156 | if (curl_multi_remove_handle(requestContext->curlm, 157 | msg->easy_handle) != CURLM_OK) { 158 | return S3StatusInternalError; 159 | } 160 | // Finish the request, ensuring that all callbacks have been made, 161 | // and also releases the request 162 | request_finish(request); 163 | // Now, since a callback was made, there may be new requests 164 | // queued up to be performed immediately, so do so 165 | status = CURLM_CALL_MULTI_PERFORM; 166 | } 167 | } while (status == CURLM_CALL_MULTI_PERFORM); 168 | 169 | return S3StatusOK; 170 | } 171 | 172 | S3Status S3_get_request_context_fdsets(S3RequestContext *requestContext, 173 | fd_set *readFdSet, fd_set *writeFdSet, 174 | fd_set *exceptFdSet, int *maxFd) 175 | { 176 | return ((curl_multi_fdset(requestContext->curlm, readFdSet, writeFdSet, 177 | exceptFdSet, maxFd) == CURLM_OK) ? 178 | S3StatusOK : S3StatusInternalError); 179 | } 180 | 181 | int64_t S3_get_request_context_timeout(S3RequestContext *requestContext) 182 | { 183 | long timeout; 184 | 185 | if (curl_multi_timeout(requestContext->curlm, &timeout) != CURLM_OK) { 186 | timeout = 0; 187 | } 188 | 189 | return timeout; 190 | } 191 | -------------------------------------------------------------------------------- /src/service.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * service.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include "request.h" 32 | 33 | 34 | typedef struct XmlCallbackData 35 | { 36 | SimpleXml simpleXml; 37 | 38 | S3ResponsePropertiesCallback *responsePropertiesCallback; 39 | S3ListServiceCallback *listServiceCallback; 40 | S3ResponseCompleteCallback *responseCompleteCallback; 41 | void *callbackData; 42 | 43 | string_buffer(ownerId, 256); 44 | string_buffer(ownerDisplayName, 256); 45 | string_buffer(bucketName, 256); 46 | string_buffer(creationDate, 128); 47 | } XmlCallbackData; 48 | 49 | 50 | static S3Status xmlCallback(const char *elementPath, const char *data, 51 | int dataLen, void *callbackData) 52 | { 53 | XmlCallbackData *cbData = (XmlCallbackData *) callbackData; 54 | 55 | int fit; 56 | 57 | if (data) { 58 | if (!strcmp(elementPath, "ListAllMyBucketsResult/Owner/ID")) { 59 | string_buffer_append(cbData->ownerId, data, dataLen, fit); 60 | } 61 | else if (!strcmp(elementPath, 62 | "ListAllMyBucketsResult/Owner/DisplayName")) { 63 | string_buffer_append(cbData->ownerDisplayName, data, dataLen, fit); 64 | } 65 | else if (!strcmp(elementPath, 66 | "ListAllMyBucketsResult/Buckets/Bucket/Name")) { 67 | string_buffer_append(cbData->bucketName, data, dataLen, fit); 68 | } 69 | else if (!strcmp 70 | (elementPath, 71 | "ListAllMyBucketsResult/Buckets/Bucket/CreationDate")) { 72 | string_buffer_append(cbData->creationDate, data, dataLen, fit); 73 | } 74 | } 75 | else { 76 | if (!strcmp(elementPath, "ListAllMyBucketsResult/Buckets/Bucket")) { 77 | // Parse date. Assume ISO-8601 date format. 78 | time_t creationDate = parseIso8601Time(cbData->creationDate); 79 | 80 | // Make the callback - a bucket just finished 81 | S3Status status = (*(cbData->listServiceCallback)) 82 | (cbData->ownerId, cbData->ownerDisplayName, 83 | cbData->bucketName, creationDate, cbData->callbackData); 84 | 85 | string_buffer_initialize(cbData->bucketName); 86 | string_buffer_initialize(cbData->creationDate); 87 | 88 | return status; 89 | } 90 | } 91 | 92 | /* Avoid compiler error about variable set but not used */ 93 | (void) fit; 94 | 95 | return S3StatusOK; 96 | } 97 | 98 | 99 | static S3Status propertiesCallback 100 | (const S3ResponseProperties *responseProperties, void *callbackData) 101 | { 102 | XmlCallbackData *cbData = (XmlCallbackData *) callbackData; 103 | 104 | return (*(cbData->responsePropertiesCallback)) 105 | (responseProperties, cbData->callbackData); 106 | } 107 | 108 | 109 | static S3Status dataCallback(int bufferSize, const char *buffer, 110 | void *callbackData) 111 | { 112 | XmlCallbackData *cbData = (XmlCallbackData *) callbackData; 113 | 114 | return simplexml_add(&(cbData->simpleXml), buffer, bufferSize); 115 | } 116 | 117 | 118 | static void completeCallback(S3Status requestStatus, 119 | const S3ErrorDetails *s3ErrorDetails, 120 | void *callbackData) 121 | { 122 | XmlCallbackData *cbData = (XmlCallbackData *) callbackData; 123 | 124 | (*(cbData->responseCompleteCallback)) 125 | (requestStatus, s3ErrorDetails, cbData->callbackData); 126 | 127 | simplexml_deinitialize(&(cbData->simpleXml)); 128 | 129 | free(cbData); 130 | } 131 | 132 | 133 | void S3_list_service(S3Protocol protocol, const char *accessKeyId, 134 | const char *secretAccessKey, const char *hostName, 135 | S3RequestContext *requestContext, 136 | const S3ListServiceHandler *handler, void *callbackData) 137 | { 138 | // Create and set up the callback data 139 | XmlCallbackData *data = 140 | (XmlCallbackData *) malloc(sizeof(XmlCallbackData)); 141 | if (!data) { 142 | (*(handler->responseHandler.completeCallback)) 143 | (S3StatusOutOfMemory, 0, callbackData); 144 | return; 145 | } 146 | 147 | simplexml_initialize(&(data->simpleXml), &xmlCallback, data); 148 | 149 | data->responsePropertiesCallback = 150 | handler->responseHandler.propertiesCallback; 151 | data->listServiceCallback = handler->listServiceCallback; 152 | data->responseCompleteCallback = handler->responseHandler.completeCallback; 153 | data->callbackData = callbackData; 154 | 155 | string_buffer_initialize(data->ownerId); 156 | string_buffer_initialize(data->ownerDisplayName); 157 | string_buffer_initialize(data->bucketName); 158 | string_buffer_initialize(data->creationDate); 159 | 160 | // Set up the RequestParams 161 | RequestParams params = 162 | { 163 | HttpRequestTypeGET, // httpRequestType 164 | { hostName, // hostName 165 | 0, // bucketName 166 | protocol, // protocol 167 | S3UriStylePath, // uriStyle 168 | accessKeyId, // accessKeyId 169 | secretAccessKey }, // secretAccessKey 170 | 0, // key 171 | 0, // queryParams 172 | 0, // subResource 173 | 0, // copySourceBucketName 174 | 0, // copySourceKey 175 | 0, // getConditions 176 | 0, // startByte 177 | 0, // byteCount 178 | 0, // requestProperties 179 | &propertiesCallback, // propertiesCallback 180 | 0, // toS3Callback 181 | 0, // toS3CallbackTotalSize 182 | &dataCallback, // fromS3Callback 183 | &completeCallback, // completeCallback 184 | data // callbackData 185 | }; 186 | 187 | // Perform the request 188 | request_perform(¶ms, requestContext); 189 | } 190 | 191 | 192 | -------------------------------------------------------------------------------- /src/response_headers_handler.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * response_headers_handler.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | #include "response_headers_handler.h" 30 | 31 | 32 | void response_headers_handler_initialize(ResponseHeadersHandler *handler) 33 | { 34 | handler->responseProperties.requestId = 0; 35 | handler->responseProperties.requestId2 = 0; 36 | handler->responseProperties.contentType = 0; 37 | handler->responseProperties.contentLength = 0; 38 | handler->responseProperties.server = 0; 39 | handler->responseProperties.eTag = 0; 40 | handler->responseProperties.lastModified = -1; 41 | handler->responseProperties.metaDataCount = 0; 42 | handler->responseProperties.metaData = 0; 43 | handler->done = 0; 44 | string_multibuffer_initialize(handler->responsePropertyStrings); 45 | string_multibuffer_initialize(handler->responseMetaDataStrings); 46 | } 47 | 48 | 49 | void response_headers_handler_add(ResponseHeadersHandler *handler, 50 | char *header, int len) 51 | { 52 | S3ResponseProperties *responseProperties = &(handler->responseProperties); 53 | char *end = &(header[len]); 54 | 55 | // Curl might call back the header function after the body has been 56 | // received, for 'chunked encoded' contents. We don't handle this as of 57 | // yet, and it's not clear that it would ever be useful. 58 | if (handler->done) { 59 | return; 60 | } 61 | 62 | // If we've already filled up the response headers, ignore this data. 63 | // This sucks, but it shouldn't happen - S3 should not be sending back 64 | // really long headers. 65 | if (handler->responsePropertyStringsSize == 66 | (sizeof(handler->responsePropertyStrings) - 1)) { 67 | return; 68 | } 69 | 70 | // It should not be possible to have a header line less than 3 long 71 | if (len < 3) { 72 | return; 73 | } 74 | 75 | // Skip whitespace at beginning of header; there never should be any, 76 | // but just to be safe 77 | while (is_blank(*header)) { 78 | header++; 79 | } 80 | 81 | // The header must end in \r\n, so skip back over it, and also over any 82 | // trailing whitespace 83 | end -= 3; 84 | while ((end > header) && is_blank(*end)) { 85 | end--; 86 | } 87 | if (!is_blank(*end)) { 88 | end++; 89 | } 90 | 91 | if (end == header) { 92 | // totally bogus 93 | return; 94 | } 95 | 96 | *end = 0; 97 | 98 | // Find the colon to split the header up 99 | char *c = header; 100 | while (*c && (*c != ':')) { 101 | c++; 102 | } 103 | 104 | int namelen = c - header; 105 | 106 | // Now walk c past the colon 107 | c++; 108 | // Now skip whitespace to the beginning of the value 109 | while (is_blank(*c)) { 110 | c++; 111 | } 112 | 113 | int valuelen = (end - c) + 1, fit; 114 | 115 | if (!strncmp(header, "x-amz-request-id", namelen)) { 116 | responseProperties->requestId = 117 | string_multibuffer_current(handler->responsePropertyStrings); 118 | string_multibuffer_add(handler->responsePropertyStrings, c, 119 | valuelen, fit); 120 | } 121 | else if (!strncmp(header, "x-amz-id-2", namelen)) { 122 | responseProperties->requestId2 = 123 | string_multibuffer_current(handler->responsePropertyStrings); 124 | string_multibuffer_add(handler->responsePropertyStrings, c, 125 | valuelen, fit); 126 | } 127 | else if (!strncmp(header, "Content-Type", namelen)) { 128 | responseProperties->contentType = 129 | string_multibuffer_current(handler->responsePropertyStrings); 130 | string_multibuffer_add(handler->responsePropertyStrings, c, 131 | valuelen, fit); 132 | } 133 | else if (!strncmp(header, "Content-Length", namelen)) { 134 | handler->responseProperties.contentLength = 0; 135 | while (*c) { 136 | handler->responseProperties.contentLength *= 10; 137 | handler->responseProperties.contentLength += (*c++ - '0'); 138 | } 139 | } 140 | else if (!strncmp(header, "Server", namelen)) { 141 | responseProperties->server = 142 | string_multibuffer_current(handler->responsePropertyStrings); 143 | string_multibuffer_add(handler->responsePropertyStrings, c, 144 | valuelen, fit); 145 | } 146 | else if (!strncmp(header, "ETag", namelen)) { 147 | responseProperties->eTag = 148 | string_multibuffer_current(handler->responsePropertyStrings); 149 | string_multibuffer_add(handler->responsePropertyStrings, c, 150 | valuelen, fit); 151 | } 152 | else if (!strncmp(header, S3_METADATA_HEADER_NAME_PREFIX, 153 | sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1)) { 154 | // Make sure there is room for another x-amz-meta header 155 | if (handler->responseProperties.metaDataCount == 156 | sizeof(handler->responseMetaData)) { 157 | return; 158 | } 159 | // Copy the name in 160 | char *metaName = &(header[sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1]); 161 | int metaNameLen = 162 | (namelen - (sizeof(S3_METADATA_HEADER_NAME_PREFIX) - 1)); 163 | char *copiedName = 164 | string_multibuffer_current(handler->responseMetaDataStrings); 165 | string_multibuffer_add(handler->responseMetaDataStrings, metaName, 166 | metaNameLen, fit); 167 | if (!fit) { 168 | return; 169 | } 170 | 171 | // Copy the value in 172 | char *copiedValue = 173 | string_multibuffer_current(handler->responseMetaDataStrings); 174 | string_multibuffer_add(handler->responseMetaDataStrings, 175 | c, valuelen, fit); 176 | if (!fit) { 177 | return; 178 | } 179 | 180 | if (!handler->responseProperties.metaDataCount) { 181 | handler->responseProperties.metaData = 182 | handler->responseMetaData; 183 | } 184 | 185 | S3NameValue *metaHeader = 186 | &(handler->responseMetaData 187 | [handler->responseProperties.metaDataCount++]); 188 | metaHeader->name = copiedName; 189 | metaHeader->value = copiedValue; 190 | } 191 | } 192 | 193 | 194 | void response_headers_handler_done(ResponseHeadersHandler *handler, CURL *curl) 195 | { 196 | // Now get the last modification time from curl, since it's easiest to let 197 | // curl parse it 198 | time_t lastModified; 199 | if (curl_easy_getinfo 200 | (curl, CURLINFO_FILETIME, &lastModified) == CURLE_OK) { 201 | handler->responseProperties.lastModified = lastModified; 202 | } 203 | 204 | handler->done = 1; 205 | } 206 | -------------------------------------------------------------------------------- /src/error_parser.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * error_parser.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include "error_parser.h" 29 | 30 | 31 | static S3Status errorXmlCallback(const char *elementPath, const char *data, 32 | int dataLen, void *callbackData) 33 | { 34 | // We ignore end of element callbacks because we don't care about them 35 | if (!data) { 36 | return S3StatusOK; 37 | } 38 | 39 | ErrorParser *errorParser = (ErrorParser *) callbackData; 40 | 41 | int fit; 42 | 43 | if (!strcmp(elementPath, "Error")) { 44 | // Ignore, this is the Error element itself, we only care about subs 45 | } 46 | else if (!strcmp(elementPath, "Error/Code")) { 47 | string_buffer_append(errorParser->code, data, dataLen, fit); 48 | } 49 | else if (!strcmp(elementPath, "Error/Message")) { 50 | string_buffer_append(errorParser->message, data, dataLen, fit); 51 | errorParser->s3ErrorDetails.message = errorParser->message; 52 | } 53 | else if (!strcmp(elementPath, "Error/Resource")) { 54 | string_buffer_append(errorParser->resource, data, dataLen, fit); 55 | errorParser->s3ErrorDetails.resource = errorParser->resource; 56 | } 57 | else if (!strcmp(elementPath, "Error/FurtherDetails")) { 58 | string_buffer_append(errorParser->furtherDetails, data, dataLen, fit); 59 | errorParser->s3ErrorDetails.furtherDetails = 60 | errorParser->furtherDetails; 61 | } 62 | else { 63 | if (strncmp(elementPath, "Error/", sizeof("Error/") - 1)) { 64 | // If for some weird reason it's not within the Error element, 65 | // ignore it 66 | return S3StatusOK; 67 | } 68 | // It's an unknown error element. See if it matches the most 69 | // recent error element. 70 | const char *elementName = &(elementPath[sizeof("Error/") - 1]); 71 | if (errorParser->s3ErrorDetails.extraDetailsCount && 72 | !strcmp(elementName, errorParser->s3ErrorDetails.extraDetails 73 | [errorParser->s3ErrorDetails.extraDetailsCount - 1].name)) { 74 | // Append the value 75 | string_multibuffer_append(errorParser->extraDetailsNamesValues, 76 | data, dataLen, fit); 77 | // If it didn't fit, remove this extra 78 | if (!fit) { 79 | errorParser->s3ErrorDetails.extraDetailsCount--; 80 | } 81 | return S3StatusOK; 82 | } 83 | // OK, must add another unknown error element, if it will fit. 84 | if (errorParser->s3ErrorDetails.extraDetailsCount == 85 | sizeof(errorParser->extraDetails)) { 86 | // Won't fit. Ignore this one. 87 | return S3StatusOK; 88 | } 89 | // Copy in the name and value 90 | char *name = string_multibuffer_current 91 | (errorParser->extraDetailsNamesValues); 92 | int nameLen = strlen(elementName); 93 | string_multibuffer_add(errorParser->extraDetailsNamesValues, 94 | elementName, nameLen, fit); 95 | if (!fit) { 96 | // Name didn't fit; ignore this one. 97 | return S3StatusOK; 98 | } 99 | char *value = string_multibuffer_current 100 | (errorParser->extraDetailsNamesValues); 101 | string_multibuffer_add(errorParser->extraDetailsNamesValues, 102 | data, dataLen, fit); 103 | if (!fit) { 104 | // Value didn't fit; ignore this one. 105 | return S3StatusOK; 106 | } 107 | S3NameValue *nv = 108 | &(errorParser->extraDetails 109 | [errorParser->s3ErrorDetails.extraDetailsCount++]); 110 | nv->name = name; 111 | nv->value = value; 112 | } 113 | 114 | return S3StatusOK; 115 | } 116 | 117 | 118 | void error_parser_initialize(ErrorParser *errorParser) 119 | { 120 | errorParser->s3ErrorDetails.message = 0; 121 | errorParser->s3ErrorDetails.resource = 0; 122 | errorParser->s3ErrorDetails.furtherDetails = 0; 123 | errorParser->s3ErrorDetails.extraDetailsCount = 0; 124 | errorParser->s3ErrorDetails.extraDetails = errorParser->extraDetails; 125 | errorParser->errorXmlParserInitialized = 0; 126 | string_buffer_initialize(errorParser->code); 127 | string_buffer_initialize(errorParser->message); 128 | string_buffer_initialize(errorParser->resource); 129 | string_buffer_initialize(errorParser->furtherDetails); 130 | string_multibuffer_initialize(errorParser->extraDetailsNamesValues); 131 | } 132 | 133 | 134 | S3Status error_parser_add(ErrorParser *errorParser, char *buffer, 135 | int bufferSize) 136 | { 137 | if (!errorParser->errorXmlParserInitialized) { 138 | simplexml_initialize(&(errorParser->errorXmlParser), &errorXmlCallback, 139 | errorParser); 140 | errorParser->errorXmlParserInitialized = 1; 141 | } 142 | 143 | return simplexml_add(&(errorParser->errorXmlParser), buffer, bufferSize); 144 | } 145 | 146 | 147 | void error_parser_convert_status(ErrorParser *errorParser, S3Status *status) 148 | { 149 | // Convert the error status string into a code 150 | if (!errorParser->codeLen) { 151 | return; 152 | } 153 | 154 | #define HANDLE_CODE(name) \ 155 | do { \ 156 | if (!strcmp(errorParser->code, #name)) { \ 157 | *status = S3StatusError##name; \ 158 | goto code_set; \ 159 | } \ 160 | } while (0) 161 | 162 | HANDLE_CODE(AccessDenied); 163 | HANDLE_CODE(AccountProblem); 164 | HANDLE_CODE(AmbiguousGrantByEmailAddress); 165 | HANDLE_CODE(BadDigest); 166 | HANDLE_CODE(BucketAlreadyExists); 167 | HANDLE_CODE(BucketAlreadyOwnedByYou); 168 | HANDLE_CODE(BucketNotEmpty); 169 | HANDLE_CODE(CredentialsNotSupported); 170 | HANDLE_CODE(CrossLocationLoggingProhibited); 171 | HANDLE_CODE(EntityTooSmall); 172 | HANDLE_CODE(EntityTooLarge); 173 | HANDLE_CODE(ExpiredToken); 174 | HANDLE_CODE(IncompleteBody); 175 | HANDLE_CODE(IncorrectNumberOfFilesInPostRequest); 176 | HANDLE_CODE(InlineDataTooLarge); 177 | HANDLE_CODE(InternalError); 178 | HANDLE_CODE(InvalidAccessKeyId); 179 | HANDLE_CODE(InvalidAddressingHeader); 180 | HANDLE_CODE(InvalidArgument); 181 | HANDLE_CODE(InvalidBucketName); 182 | HANDLE_CODE(InvalidDigest); 183 | HANDLE_CODE(InvalidLocationConstraint); 184 | HANDLE_CODE(InvalidPayer); 185 | HANDLE_CODE(InvalidPolicyDocument); 186 | HANDLE_CODE(InvalidRange); 187 | HANDLE_CODE(InvalidSecurity); 188 | HANDLE_CODE(InvalidSOAPRequest); 189 | HANDLE_CODE(InvalidStorageClass); 190 | HANDLE_CODE(InvalidTargetBucketForLogging); 191 | HANDLE_CODE(InvalidToken); 192 | HANDLE_CODE(InvalidURI); 193 | HANDLE_CODE(KeyTooLong); 194 | HANDLE_CODE(MalformedACLError); 195 | HANDLE_CODE(MalformedXML); 196 | HANDLE_CODE(MaxMessageLengthExceeded); 197 | HANDLE_CODE(MaxPostPreDataLengthExceededError); 198 | HANDLE_CODE(MetadataTooLarge); 199 | HANDLE_CODE(MethodNotAllowed); 200 | HANDLE_CODE(MissingAttachment); 201 | HANDLE_CODE(MissingContentLength); 202 | HANDLE_CODE(MissingSecurityElement); 203 | HANDLE_CODE(MissingSecurityHeader); 204 | HANDLE_CODE(NoLoggingStatusForKey); 205 | HANDLE_CODE(NoSuchBucket); 206 | HANDLE_CODE(NoSuchKey); 207 | HANDLE_CODE(NotImplemented); 208 | HANDLE_CODE(NotSignedUp); 209 | HANDLE_CODE(OperationAborted); 210 | HANDLE_CODE(PermanentRedirect); 211 | HANDLE_CODE(PreconditionFailed); 212 | HANDLE_CODE(Redirect); 213 | HANDLE_CODE(RequestIsNotMultiPartContent); 214 | HANDLE_CODE(RequestTimeout); 215 | HANDLE_CODE(RequestTimeTooSkewed); 216 | HANDLE_CODE(RequestTorrentOfBucketError); 217 | HANDLE_CODE(SignatureDoesNotMatch); 218 | HANDLE_CODE(SlowDown); 219 | HANDLE_CODE(TemporaryRedirect); 220 | HANDLE_CODE(TokenRefreshRequired); 221 | HANDLE_CODE(TooManyBuckets); 222 | HANDLE_CODE(UnexpectedContent); 223 | HANDLE_CODE(UnresolvableGrantByEmailAddress); 224 | HANDLE_CODE(UserKeyMustBeSpecified); 225 | *status = S3StatusErrorUnknown; 226 | 227 | code_set: 228 | 229 | return; 230 | } 231 | 232 | 233 | // Always call this 234 | void error_parser_deinitialize(ErrorParser *errorParser) 235 | { 236 | if (errorParser->errorXmlParserInitialized) { 237 | simplexml_deinitialize(&(errorParser->errorXmlParser)); 238 | } 239 | } 240 | -------------------------------------------------------------------------------- /GNUmakefile.mingw: -------------------------------------------------------------------------------- 1 | # GNUmakefile.mingw 2 | # 3 | # Copyright 2008 Bryan Ischo 4 | # 5 | # This file is part of libs3. 6 | # 7 | # libs3 is free software: you can redistribute it and/or modify it under the 8 | # terms of the GNU General Public License as published by the Free Software 9 | # Foundation, version 3 of the License. 10 | # 11 | # In addition, as a special exception, the copyright holders give 12 | # permission to link the code of this library and its programs with the 13 | # OpenSSL library, and distribute linked combinations including the two. 14 | # 15 | # libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | # 20 | # You should have received a copy of the GNU General Public License version 3 21 | # along with libs3, in a file named COPYING. If not, see 22 | # . 23 | 24 | # I tried to use the autoconf/automake/autolocal/etc (i.e. autohell) tools 25 | # but I just couldn't stomach them. Since this is a Makefile for POSIX 26 | # systems, I will simply do away with autohell completely and use a GNU 27 | # Makefile. GNU make ought to be available pretty much everywhere, so I 28 | # don't see this being a significant issue for portability. 29 | 30 | # All commands assume a GNU compiler. For systems which do not use a GNU 31 | # compiler, write scripts with the same names as these commands, and taking 32 | # the same arguments, and translate the arguments and commands into the 33 | # appropriate non-POSIX ones as needed. libs3 assumes a GNU toolchain as 34 | # the most portable way to build software possible. Non-POSIX, non-GNU 35 | # systems can do the work of supporting this build infrastructure. 36 | 37 | 38 | # -------------------------------------------------------------------------- 39 | # Set libs3 version number, unless it is already set. 40 | # This is trunk0.trunk0 on the libs3 git master branch; release branches 41 | # are created with this set to specific version numbers when releases are 42 | # made. 43 | 44 | LIBS3_VER_MAJOR ?= trunk0 45 | LIBS3_VER_MINOR ?= trunk0 46 | LIBS3_VER := $(LIBS3_VER_MAJOR).$(LIBS3_VER_MINOR) 47 | 48 | 49 | # ----------------------------------------------------------------------------- 50 | # Determine verbosity. VERBOSE_SHOW should be prepended to every command which 51 | # should only be displayed if VERBOSE is set. QUIET_ECHO may be used to 52 | # echo text only if VERBOSE is not set. Typically, a VERBOSE_SHOW command will 53 | # be paired with a QUIET_ECHO command, to provide a command which is displayed 54 | # in VERBOSE mode, along with text which is displayed in non-VERBOSE mode to 55 | # describe the command. 56 | # 57 | # No matter what VERBOSE is defined to, it ends up as true if it's defined. 58 | # This will be weird if you defined VERBOSE=false in the environment, and we 59 | # switch it to true here; but the meaning of VERBOSE is, "if it's defined to 60 | # any value, then verbosity is turned on". So don't define VERBOSE if you 61 | # don't want verbosity in the build process. 62 | # ----------------------------------------------------------------------------- 63 | 64 | ifdef VERBOSE 65 | VERBOSE = true 66 | VERBOSE_ECHO = @ echo 67 | VERBOSE_SHOW = 68 | QUIET_ECHO = @ echo >nul 69 | else 70 | VERBOSE = false 71 | VERBOSE_ECHO = @ echo >nul 72 | VERBOSE_SHOW = @ 73 | QUIET_ECHO = @ echo 74 | endif 75 | 76 | 77 | # -------------------------------------------------------------------------- 78 | # BUILD directory 79 | ifndef BUILD 80 | ifdef DEBUG 81 | BUILD := build-debug 82 | else 83 | BUILD := build 84 | endif 85 | endif 86 | 87 | 88 | # -------------------------------------------------------------------------- 89 | # DESTDIR directory 90 | ifndef DESTDIR 91 | DESTDIR := libs3-$(LIBS3_VER) 92 | endif 93 | 94 | 95 | # -------------------------------------------------------------------------- 96 | # Acquire configuration information for libraries that libs3 depends upon 97 | 98 | ifndef CURL_LIBS 99 | CURL_LIBS := -Lc:\libs3-libs\bin -lcurl 100 | endif 101 | 102 | ifndef CURL_CFLAGS 103 | CURL_CFLAGS := -Ic:\libs3-libs\include 104 | endif 105 | 106 | ifndef LIBXML2_LIBS 107 | LIBXML2_LIBS := -Lc:\libs3-libs\bin -lxml2 108 | endif 109 | 110 | ifndef LIBXML2_CFLAGS 111 | LIBXML2_CFLAGS := -Ic:\libs3-libs\include 112 | endif 113 | 114 | 115 | # -------------------------------------------------------------------------- 116 | # These CFLAGS assume a GNU compiler. For other compilers, write a script 117 | # which converts these arguments into their equivalent for that particular 118 | # compiler. 119 | 120 | ifndef CFLAGS 121 | ifdef DEBUG 122 | CFLAGS := -g 123 | else 124 | CFLAGS := -O3 125 | endif 126 | endif 127 | 128 | CFLAGS += -Wall -Werror -Wshadow -Wextra -Iinc \ 129 | $(CURL_CFLAGS) $(LIBXML2_CFLAGS) \ 130 | -DLIBS3_VER_MAJOR=\"$(LIBS3_VER_MAJOR)\" \ 131 | -DLIBS3_VER_MINOR=\"$(LIBS3_VER_MINOR)\" \ 132 | -DLIBS3_VER=\"$(LIBS3_VER)\" \ 133 | -D__STRICT_ANSI__ \ 134 | -D_ISOC99_SOURCE \ 135 | -D_POSIX_C_SOURCE=200112L \ 136 | -Dsleep=Sleep -DSLEEP_UNITS_PER_SECOND=1000 \ 137 | -DFOPEN_EXTRA_FLAGS=\"b\" \ 138 | -Iinc/mingw -include windows.h 139 | 140 | LDFLAGS = $(CURL_LIBS) $(LIBXML2_LIBS) 141 | 142 | # -------------------------------------------------------------------------- 143 | # Default targets are everything 144 | 145 | .PHONY: all 146 | all: exported test 147 | 148 | 149 | # -------------------------------------------------------------------------- 150 | # Exported targets are the library and driver program 151 | 152 | .PHONY: exported 153 | exported: libs3 s3 headers 154 | 155 | 156 | # -------------------------------------------------------------------------- 157 | # Install target 158 | 159 | .PHONY: install 160 | install: exported 161 | $(QUIET_ECHO) $(DESTDIR)/bin/s3.exe: Installing executable 162 | - @ mkdir $(DESTDIR)\bin 2>&1 | echo >nul 163 | $(VERBOSE_SHOW) copy $(BUILD)\bin\s3.exe $(DESTDIR)\bin\s3.exe >nul 164 | $(QUIET_ECHO) $(DESTDIR)/bin/libs3/dll: Installing dynamic library 165 | $(VERBOSE_SHOW) copy $(BUILD)\bin\libs3.dll $(DESTDIR)\bin\libs3.dll >nul 166 | $(QUIET_ECHO) $(DESTDIR)/lib/libs3.a: Installing static library 167 | - @ mkdir $(DESTDIR)\lib 2>&1 | echo >nul 168 | $(VERBOSE_SHOW) copy $(BUILD)\lib\libs3.a $(DESTDIR)\lib\libs3.a >nul 169 | $(QUIET_ECHO) $(DESTDIR)/lib/libs3.def: Installing def file 170 | $(VERBOSE_SHOW) copy mswin\libs3.def $(DESTDIR)\lib\libs3.def >nul 171 | - @ mkdir $(DESTDIR)\include 2>&1 | echo >nul 172 | $(QUIET_ECHO) $(DESTDIR)/include/libs3.h: Copying header 173 | $(VERBOSE_SHOW) copy $(BUILD)\include\libs3.h \ 174 | $(DESTDIR)\include\libs3.h >nul 175 | $(QUIET_ECHO) $(DESTDIR)/LICENSE: Copying license 176 | $(VERBOSE_SHOW) copy LICENSE $(DESTDIR)\LICENSE >nul 177 | $(QUIET_ECHO) $(DESTDIR)/COPYING: Copying license 178 | $(VERBOSE_SHOW) copy COPYING $(DESTDIR)\COPYING >nul 179 | 180 | 181 | # -------------------------------------------------------------------------- 182 | # Uninstall target 183 | 184 | .PHONY: uninstall 185 | uninstall: 186 | $(QUIET_ECHO) Installed files: Uninstalling 187 | $(VERBOSE_SHOW) \ 188 | del $(DESTDIR)\bin\s3.exe \ 189 | $(DESTDIR)\bin\libs3.dll \ 190 | $(DESTDIR)\lib\libs3.a \ 191 | $(DESTDIR)\lib\libs3.def \ 192 | $(DESTDIR)\include\libs3.h \ 193 | $(DESTDIR)\LICENSE \ 194 | $(DESTDIR)\COPYING 195 | 196 | 197 | # -------------------------------------------------------------------------- 198 | # Compile target patterns 199 | 200 | $(BUILD)/obj/%.o: src/%.c 201 | $(QUIET_ECHO) $@: Compiling object 202 | - @ mkdir $(subst /,\,$(dir $(BUILD)/dep/$<)) 2>&1 | echo >nul 203 | @ gcc $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ 204 | -o $(BUILD)/dep/$(<:%.c=%.d) -c $< 205 | - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul 206 | $(VERBOSE_SHOW) gcc $(CFLAGS) -o $@ -c $< 207 | 208 | 209 | # -------------------------------------------------------------------------- 210 | # libs3 library targets 211 | 212 | LIBS3_SHARED = $(BUILD)/bin/libs3.dll 213 | LIBS3_STATIC = $(BUILD)/lib/libs3.a 214 | 215 | .PHONY: libs3 216 | libs3: $(LIBS3_SHARED) $(BUILD)/lib/libs3.a 217 | 218 | LIBS3_SOURCES := src/acl.c src/bucket.c src/error_parser.c src/general.c \ 219 | src/object.c src/request.c src/request_context.c \ 220 | src/response_headers_handler.c src/service_access_logging.c \ 221 | src/service.c src/simplexml.c src/util.c src/mingw_functions.c 222 | 223 | $(LIBS3_SHARED): $(LIBS3_SOURCES:src/%.c=$(BUILD)/obj/%.o) 224 | $(QUIET_ECHO) $@: Building dynamic library 225 | - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul 226 | $(VERBOSE_SHOW) gcc -shared -o $@ $^ $(LDFLAGS) -lws2_32 227 | 228 | $(LIBS3_STATIC): $(LIBS3_SHARED) 229 | $(QUIET_ECHO) $@: Building static library 230 | - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul 231 | $(VERBOSE_SHOW) dlltool --def mswin\libs3.def --dllname $(subst /,\,$<) \ 232 | --output-lib $(subst /,\,$@) 233 | 234 | 235 | # -------------------------------------------------------------------------- 236 | # Driver program targets 237 | 238 | .PHONY: s3 239 | s3: $(BUILD)/bin/s3.exe 240 | 241 | $(BUILD)/bin/s3.exe: $(BUILD)/obj/s3.o $(BUILD)/obj/mingw_s3_functions.o \ 242 | $(BUILD)/lib/libs3.a 243 | $(QUIET_ECHO) $@: Building executable 244 | - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul 245 | $(VERBOSE_SHOW) gcc -o $@ $^ $(LDFLAGS) -lws2_32 246 | 247 | 248 | # -------------------------------------------------------------------------- 249 | # libs3 header targets 250 | 251 | .PHONY: headers 252 | headers: $(BUILD)\include\libs3.h 253 | 254 | $(BUILD)\include\libs3.h: inc\libs3.h 255 | $(QUIET_ECHO) $@: Copying header 256 | - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul 257 | $(VERBOSE_SHOW) copy $< $@ 258 | 259 | 260 | # -------------------------------------------------------------------------- 261 | # Test targets 262 | 263 | .PHONY: test 264 | test: $(BUILD)/bin/testsimplexml 265 | 266 | $(BUILD)/bin/testsimplexml: $(BUILD)/obj/testsimplexml.o \ 267 | $(BUILD)/obj/simplexml.o 268 | $(QUIET_ECHO) $@: Building executable 269 | - @ mkdir $(subst /,\,$(dir $@)) 2>&1 | echo >nul 270 | $(VERBOSE_SHOW) gcc -o $@ $^ $(LIBXML2_LIBS) 271 | 272 | 273 | # -------------------------------------------------------------------------- 274 | # Clean target 275 | 276 | .PHONY: clean 277 | clean: 278 | $(QUIET_ECHO) $(BUILD): Cleaning 279 | $(VERBOSE_SHOW) mswin\rmrf.bat $(BUILD) 280 | 281 | 282 | # -------------------------------------------------------------------------- 283 | # Clean dependencies target 284 | 285 | .PHONY: cleandeps 286 | cleandeps: 287 | $(QUIET_ECHO) $(BUILD)/dep: Cleaning dependencies 288 | $(VERBOSE_SHOW) mswin\rmrf.bat $(BUILD)\dep 289 | 290 | 291 | # -------------------------------------------------------------------------- 292 | # Dependencies 293 | 294 | ALL_SOURCES := $(LIBS3_SOURCES) s3.c testsimplexml.c 295 | 296 | $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.d))) 297 | -------------------------------------------------------------------------------- /GNUmakefile.osx: -------------------------------------------------------------------------------- 1 | # GNUmakefile.osx 2 | # 3 | # Copyright 2008 Bryan Ischo 4 | # 5 | # This file is part of libs3. 6 | # 7 | # libs3 is free software: you can redistribute it and/or modify it under the 8 | # terms of the GNU General Public License as published by the Free Software 9 | # Foundation, version 3 of the License. 10 | # 11 | # In addition, as a special exception, the copyright holders give 12 | # permission to link the code of this library and its programs with the 13 | # OpenSSL library, and distribute linked combinations including the two. 14 | # 15 | # libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | # 20 | # You should have received a copy of the GNU General Public License version 3 21 | # along with libs3, in a file named COPYING. If not, see 22 | # . 23 | 24 | # I tried to use the autoconf/automake/autolocal/etc (i.e. autohell) tools 25 | # but I just couldn't stomach them. Since this is a Makefile for POSIX 26 | # systems, I will simply do away with autohell completely and use a GNU 27 | # Makefile. GNU make ought to be available pretty much everywhere, so I 28 | # don't see this being a significant issue for portability. 29 | 30 | # All commands assume a GNU compiler. For systems which do not use a GNU 31 | # compiler, write scripts with the same names as these commands, and taking 32 | # the same arguments, and translate the arguments and commands into the 33 | # appropriate non-POSIX ones as needed. libs3 assumes a GNU toolchain as 34 | # the most portable way to build software possible. Non-POSIX, non-GNU 35 | # systems can do the work of supporting this build infrastructure. 36 | 37 | 38 | # -------------------------------------------------------------------------- 39 | # Set libs3 version number, unless it is already set. 40 | # This is trunk0.trunk0 on the libs3 git master branch; release branches 41 | # are created with this set to specific version numbers when releases are 42 | # made. 43 | 44 | LIBS3_VER_MAJOR ?= trunk0 45 | LIBS3_VER_MINOR ?= trunk0 46 | LIBS3_VER := $(LIBS3_VER_MAJOR).$(LIBS3_VER_MINOR) 47 | 48 | 49 | # ----------------------------------------------------------------------------- 50 | # Determine verbosity. VERBOSE_SHOW should be prepended to every command which 51 | # should only be displayed if VERBOSE is set. QUIET_ECHO may be used to 52 | # echo text only if VERBOSE is not set. Typically, a VERBOSE_SHOW command will 53 | # be paired with a QUIET_ECHO command, to provide a command which is displayed 54 | # in VERBOSE mode, along with text which is displayed in non-VERBOSE mode to 55 | # describe the command. 56 | # 57 | # No matter what VERBOSE is defined to, it ends up as true if it's defined. 58 | # This will be weird if you defined VERBOSE=false in the environment, and we 59 | # switch it to true here; but the meaning of VERBOSE is, "if it's defined to 60 | # any value, then verbosity is turned on". So don't define VERBOSE if you 61 | # don't want verbosity in the build process. 62 | # ----------------------------------------------------------------------------- 63 | 64 | ifdef VERBOSE 65 | VERBOSE = true 66 | VERBOSE_ECHO = @ echo 67 | VERBOSE_SHOW = 68 | QUIET_ECHO = @ echo > /dev/null 69 | else 70 | VERBOSE = false 71 | VERBOSE_ECHO = @ echo > /dev/null 72 | VERBOSE_SHOW = @ 73 | QUIET_ECHO = @ echo 74 | endif 75 | 76 | 77 | # -------------------------------------------------------------------------- 78 | # BUILD directory 79 | ifndef BUILD 80 | ifdef DEBUG 81 | BUILD := build-debug 82 | else 83 | BUILD := build 84 | endif 85 | endif 86 | 87 | 88 | # -------------------------------------------------------------------------- 89 | # DESTDIR directory 90 | ifndef DESTDIR 91 | DESTDIR := /usr 92 | endif 93 | 94 | 95 | # -------------------------------------------------------------------------- 96 | # Acquire configuration information for libraries that libs3 depends upon 97 | 98 | ifndef CURL_LIBS 99 | CURL_LIBS := $(shell curl-config --libs) 100 | endif 101 | 102 | ifndef CURL_CFLAGS 103 | CURL_CFLAGS := $(shell curl-config --cflags) 104 | endif 105 | 106 | ifndef LIBXML2_LIBS 107 | LIBXML2_LIBS := $(shell xml2-config --libs) 108 | endif 109 | 110 | ifndef LIBXML2_CFLAGS 111 | LIBXML2_CFLAGS := $(shell xml2-config --cflags) 112 | endif 113 | 114 | 115 | # -------------------------------------------------------------------------- 116 | # These CFLAGS assume a GNU compiler. For other compilers, write a script 117 | # which converts these arguments into their equivalent for that particular 118 | # compiler. 119 | 120 | ifndef CFLAGS 121 | ifdef DEBUG 122 | CFLAGS := -g 123 | else 124 | CFLAGS := -O3 125 | endif 126 | endif 127 | 128 | CFLAGS += -Wall -Werror -Wshadow -Wextra -Iinc \ 129 | $(CURL_CFLAGS) $(LIBXML2_CFLAGS) \ 130 | -DLIBS3_VER_MAJOR=\"$(LIBS3_VER_MAJOR)\" \ 131 | -DLIBS3_VER_MINOR=\"$(LIBS3_VER_MINOR)\" \ 132 | -DLIBS3_VER=\"$(LIBS3_VER)\" \ 133 | -D__STRICT_ANSI__ \ 134 | -D_ISOC99_SOURCE \ 135 | -fno-common 136 | 137 | LDFLAGS = $(CURL_LIBS) $(LIBXML2_LIBS) -lpthread 138 | 139 | 140 | # -------------------------------------------------------------------------- 141 | # Default targets are everything 142 | 143 | .PHONY: all 144 | all: exported test 145 | 146 | 147 | # -------------------------------------------------------------------------- 148 | # Exported targets are the library and driver program 149 | 150 | .PHONY: exported 151 | exported: libs3 s3 headers 152 | 153 | 154 | # -------------------------------------------------------------------------- 155 | # Install target 156 | 157 | .PHONY: install 158 | install: exported 159 | $(QUIET_ECHO) $(DESTDIR)/bin/s3: Installing executable 160 | $(VERBOSE_SHOW) install -ps -m u+rwx,go+rx $(BUILD)/bin/s3 \ 161 | $(DESTDIR)/bin/s3 162 | $(QUIET_ECHO) \ 163 | $(DESTDIR)/lib/libs3.$(LIBS3_VER).dylib: Installing dynamic library 164 | $(VERBOSE_SHOW) install -p -m u+rw,go+r \ 165 | $(BUILD)/lib/libs3.$(LIBS3_VER_MAJOR).dylib \ 166 | $(DESTDIR)/lib/libs3.$(LIBS3_VER).dylib 167 | $(QUIET_ECHO) \ 168 | $(DESTDIR)/lib/libs3.$(LIBS3_VER_MAJOR).dylib: Linking dynamic library 169 | $(VERBOSE_SHOW) ln -sf libs3.$(LIBS3_VER).dylib \ 170 | $(DESTDIR)/lib/libs3.$(LIBS3_VER_MAJOR).dylib 171 | $(QUIET_ECHO) $(DESTDIR)/lib/libs3.dylib: Linking dynamic library 172 | $(VERBOSE_SHOW) ln -sf libs3.$(LIBS3_VER_MAJOR).dylib \ 173 | $(DESTDIR)/lib/libs3.dylib 174 | $(QUIET_ECHO) $(DESTDIR)/lib/libs3.a: Installing static library 175 | $(VERBOSE_SHOW) install -p -m u+rw,go+r $(BUILD)/lib/libs3.a \ 176 | $(DESTDIR)/lib/libs3.a 177 | $(QUIET_ECHO) $(DESTDIR)/include/libs3.h: Installing header 178 | $(VERBOSE_SHOW) install -p -m u+rw,go+r $(BUILD)/include/libs3.h \ 179 | $(DESTDIR)/include/libs3.h 180 | 181 | 182 | # -------------------------------------------------------------------------- 183 | # Uninstall target 184 | 185 | .PHONY: uninstall 186 | uninstall: 187 | $(QUIET_ECHO) Installed files: Uninstalling 188 | $(VERBOSE_SHOW) \ 189 | rm -f $(DESTDIR)/bin/s3 \ 190 | $(DESTDIR)/lib/libs3.dylib \ 191 | $(DESTDIR)/lib/libs3.$(LIBS3_VER_MAJOR).dylib \ 192 | $(DESTDIR)/lib/libs3.$(LIBS3_VER).dylib \ 193 | $(DESTDIR)/lib/libs3.a \ 194 | $(DESTDIR)/include/libs3.h 195 | 196 | 197 | # -------------------------------------------------------------------------- 198 | # Compile target patterns 199 | 200 | $(BUILD)/obj/%.o: src/%.c 201 | $(QUIET_ECHO) $@: Compiling object 202 | @ mkdir -p $(dir $(BUILD)/dep/$<) 203 | @ gcc $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ 204 | -o $(BUILD)/dep/$(<:%.c=%.d) -c $< 205 | @ mkdir -p $(dir $@) 206 | @(VERBOSE_SHOW) gcc $(CFLAGS) -o $@ -c $< 207 | 208 | $(BUILD)/obj/%.do: src/%.c 209 | $(QUIET_ECHO) $@: Compiling dynamic object 210 | @ mkdir -p $(dir $(BUILD)/dep/$<) 211 | @ gcc $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ 212 | -o $(BUILD)/dep/$(<:%.c=%.dd) -c $< 213 | @ mkdir -p $(dir $@) 214 | $(VERBOSE_SHOW) gcc $(CFLAGS) -fpic -fPIC -o $@ -c $< 215 | 216 | 217 | # -------------------------------------------------------------------------- 218 | # libs3 library targets 219 | 220 | LIBS3_SHARED = $(BUILD)/lib/libs3.$(LIBS3_VER_MAJOR).dylib 221 | LIBS3_STATIC = $(BUILD)/lib/libs3.a 222 | 223 | .PHONY: libs3 224 | libs3: $(LIBS3_SHARED) $(LIBS3_SHARED_MAJOR) $(BUILD)/lib/libs3.a 225 | 226 | LIBS3_SOURCES := src/acl.c src/bucket.c src/error_parser.c src/general.c \ 227 | src/object.c src/request.c src/request_context.c \ 228 | src/response_headers_handler.c src/service_access_logging.c \ 229 | src/service.c src/simplexml.c src/util.c 230 | 231 | $(LIBS3_SHARED): $(LIBS3_SOURCES:src/%.c=$(BUILD)/obj/%.do) 232 | $(QUIET_ECHO) $@: Building shared library 233 | @ mkdir -p $(dir $@) 234 | $(VERBOSE_SHOW) gcc -dynamiclib -install_name \ 235 | libs3.$(LIBS3_VER_MAJOR).dylib \ 236 | -compatibility_version $(LIBS3_VER_MAJOR) \ 237 | -current_version $(LIBS3_VER) -o $@ $^ $(LDFLAGS) 238 | 239 | $(LIBS3_STATIC): $(LIBS3_SOURCES:src/%.c=$(BUILD)/obj/%.o) 240 | $(QUIET_ECHO) $@: Building static library 241 | @ mkdir -p $(dir $@) 242 | $(VERBOSE_SHOW) $(AR) cr $@ $^ 243 | 244 | 245 | # -------------------------------------------------------------------------- 246 | # Driver program targets 247 | 248 | .PHONY: s3 249 | s3: $(BUILD)/bin/s3 250 | 251 | $(BUILD)/bin/s3: $(BUILD)/obj/s3.o $(LIBS3_SHARED) 252 | $(QUIET_ECHO) $@: Building executable 253 | @ mkdir -p $(dir $@) 254 | $(VERBOSE_SHOW) gcc -o $@ $^ $(LDFLAGS) 255 | 256 | 257 | # -------------------------------------------------------------------------- 258 | # libs3 header targets 259 | 260 | .PHONY: headers 261 | headers: $(BUILD)/include/libs3.h 262 | 263 | $(BUILD)/include/libs3.h: inc/libs3.h 264 | $(QUIET_ECHO) $@: Linking header 265 | @ mkdir -p $(dir $@) 266 | $(VERBOSE_SHOW) ln -sf $(abspath $<) $@ 267 | 268 | 269 | # -------------------------------------------------------------------------- 270 | # Test targets 271 | 272 | .PHONY: test 273 | test: $(BUILD)/bin/testsimplexml 274 | 275 | $(BUILD)/bin/testsimplexml: $(BUILD)/obj/testsimplexml.o $(LIBS3_STATIC) 276 | $(QUIET_ECHO) $@: Building executable 277 | @ mkdir -p $(dir $@) 278 | $(VERBOSE_SHOW) gcc -o $@ $^ $(LIBXML2_LIBS) 279 | 280 | 281 | # -------------------------------------------------------------------------- 282 | # Clean target 283 | 284 | .PHONY: clean 285 | clean: 286 | $(QUIET_ECHO) $(BUILD): Cleaning 287 | $(VERBOSE_SHOW) rm -rf $(BUILD) 288 | 289 | 290 | # -------------------------------------------------------------------------- 291 | # Clean dependencies target 292 | 293 | .PHONY: cleandeps 294 | cleandeps: 295 | $(QUIET_ECHO) $(BUILD)/dep: Cleaning dependencies 296 | $(VERBOSE_SHOW) rm -rf $(BUILD)/dep 297 | 298 | 299 | # -------------------------------------------------------------------------- 300 | # Dependencies 301 | 302 | ALL_SOURCES := $(LIBS3_SOURCES) s3.c testsimplexml.c 303 | 304 | $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.d))) 305 | $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.dd))) 306 | -------------------------------------------------------------------------------- /src/acl.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * acl.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | #include "libs3.h" 30 | #include "request.h" 31 | 32 | // Use a rather arbitrary max size for the document of 64K 33 | #define ACL_XML_DOC_MAXSIZE (64 * 1024) 34 | 35 | 36 | // get acl ------------------------------------------------------------------- 37 | 38 | typedef struct GetAclData 39 | { 40 | SimpleXml simpleXml; 41 | 42 | S3ResponsePropertiesCallback *responsePropertiesCallback; 43 | S3ResponseCompleteCallback *responseCompleteCallback; 44 | void *callbackData; 45 | 46 | int *aclGrantCountReturn; 47 | S3AclGrant *aclGrants; 48 | char *ownerId; 49 | char *ownerDisplayName; 50 | string_buffer(aclXmlDocument, ACL_XML_DOC_MAXSIZE); 51 | } GetAclData; 52 | 53 | 54 | static S3Status getAclPropertiesCallback 55 | (const S3ResponseProperties *responseProperties, void *callbackData) 56 | { 57 | GetAclData *gaData = (GetAclData *) callbackData; 58 | 59 | return (*(gaData->responsePropertiesCallback)) 60 | (responseProperties, gaData->callbackData); 61 | } 62 | 63 | 64 | static S3Status getAclDataCallback(int bufferSize, const char *buffer, 65 | void *callbackData) 66 | { 67 | GetAclData *gaData = (GetAclData *) callbackData; 68 | 69 | int fit; 70 | 71 | string_buffer_append(gaData->aclXmlDocument, buffer, bufferSize, fit); 72 | 73 | return fit ? S3StatusOK : S3StatusXmlDocumentTooLarge; 74 | } 75 | 76 | 77 | static void getAclCompleteCallback(S3Status requestStatus, 78 | const S3ErrorDetails *s3ErrorDetails, 79 | void *callbackData) 80 | { 81 | GetAclData *gaData = (GetAclData *) callbackData; 82 | 83 | if (requestStatus == S3StatusOK) { 84 | // Parse the document 85 | requestStatus = S3_convert_acl 86 | (gaData->aclXmlDocument, gaData->ownerId, gaData->ownerDisplayName, 87 | gaData->aclGrantCountReturn, gaData->aclGrants); 88 | } 89 | 90 | (*(gaData->responseCompleteCallback)) 91 | (requestStatus, s3ErrorDetails, gaData->callbackData); 92 | 93 | free(gaData); 94 | } 95 | 96 | 97 | void S3_get_acl(const S3BucketContext *bucketContext, const char *key, 98 | char *ownerId, char *ownerDisplayName, 99 | int *aclGrantCountReturn, S3AclGrant *aclGrants, 100 | S3RequestContext *requestContext, 101 | const S3ResponseHandler *handler, void *callbackData) 102 | { 103 | // Create the callback data 104 | GetAclData *gaData = (GetAclData *) malloc(sizeof(GetAclData)); 105 | if (!gaData) { 106 | (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); 107 | return; 108 | } 109 | 110 | gaData->responsePropertiesCallback = handler->propertiesCallback; 111 | gaData->responseCompleteCallback = handler->completeCallback; 112 | gaData->callbackData = callbackData; 113 | 114 | gaData->aclGrantCountReturn = aclGrantCountReturn; 115 | gaData->aclGrants = aclGrants; 116 | gaData->ownerId = ownerId; 117 | gaData->ownerDisplayName = ownerDisplayName; 118 | string_buffer_initialize(gaData->aclXmlDocument); 119 | *aclGrantCountReturn = 0; 120 | 121 | // Set up the RequestParams 122 | RequestParams params = 123 | { 124 | HttpRequestTypeGET, // httpRequestType 125 | { bucketContext->hostName, // hostName 126 | bucketContext->bucketName, // bucketName 127 | bucketContext->protocol, // protocol 128 | bucketContext->uriStyle, // uriStyle 129 | bucketContext->accessKeyId, // accessKeyId 130 | bucketContext->secretAccessKey }, // secretAccessKey 131 | key, // key 132 | 0, // queryParams 133 | "acl", // subResource 134 | 0, // copySourceBucketName 135 | 0, // copySourceKey 136 | 0, // getConditions 137 | 0, // startByte 138 | 0, // byteCount 139 | 0, // putProperties 140 | &getAclPropertiesCallback, // propertiesCallback 141 | 0, // toS3Callback 142 | 0, // toS3CallbackTotalSize 143 | &getAclDataCallback, // fromS3Callback 144 | &getAclCompleteCallback, // completeCallback 145 | gaData // callbackData 146 | }; 147 | 148 | // Perform the request 149 | request_perform(¶ms, requestContext); 150 | } 151 | 152 | 153 | // set acl ------------------------------------------------------------------- 154 | 155 | static S3Status generateAclXmlDocument(const char *ownerId, 156 | const char *ownerDisplayName, 157 | int aclGrantCount, 158 | const S3AclGrant *aclGrants, 159 | int *xmlDocumentLenReturn, 160 | char *xmlDocument, 161 | int xmlDocumentBufferSize) 162 | { 163 | *xmlDocumentLenReturn = 0; 164 | 165 | #define append(fmt, ...) \ 166 | do { \ 167 | *xmlDocumentLenReturn += snprintf \ 168 | (&(xmlDocument[*xmlDocumentLenReturn]), \ 169 | xmlDocumentBufferSize - *xmlDocumentLenReturn - 1, \ 170 | fmt, __VA_ARGS__); \ 171 | if (*xmlDocumentLenReturn >= xmlDocumentBufferSize) { \ 172 | return S3StatusXmlDocumentTooLarge; \ 173 | } \ 174 | } while (0) 175 | 176 | append("%s%s" 177 | "", ownerId, 178 | ownerDisplayName); 179 | 180 | int i; 181 | for (i = 0; i < aclGrantCount; i++) { 182 | append("%s", "granteeType) { 186 | case S3GranteeTypeAmazonCustomerByEmail: 187 | append("AmazonCustomerByEmail\">%s", 188 | grant->grantee.amazonCustomerByEmail.emailAddress); 189 | break; 190 | case S3GranteeTypeCanonicalUser: 191 | append("CanonicalUser\">%s%s", 192 | grant->grantee.canonicalUser.id, 193 | grant->grantee.canonicalUser.displayName); 194 | break; 195 | default: { // case S3GranteeTypeAllAwsUsers/S3GranteeTypeAllUsers: 196 | const char *grantee; 197 | switch (grant->granteeType) { 198 | case S3GranteeTypeAllAwsUsers: 199 | grantee = ACS_GROUP_AWS_USERS; 200 | break; 201 | case S3GranteeTypeAllUsers: 202 | grantee = ACS_GROUP_ALL_USERS; 203 | break; 204 | default: 205 | grantee = ACS_GROUP_LOG_DELIVERY; 206 | break; 207 | } 208 | append("Group\">%s", grantee); 209 | } 210 | break; 211 | } 212 | append("%s", 213 | ((grant->permission == S3PermissionRead) ? "READ" : 214 | (grant->permission == S3PermissionWrite) ? "WRITE" : 215 | (grant->permission == S3PermissionReadACP) ? "READ_ACP" : 216 | (grant->permission == S3PermissionWriteACP) ? "WRITE_ACP" : 217 | "FULL_CONTROL")); 218 | } 219 | 220 | append("%s", ""); 221 | 222 | return S3StatusOK; 223 | } 224 | 225 | 226 | typedef struct SetAclData 227 | { 228 | S3ResponsePropertiesCallback *responsePropertiesCallback; 229 | S3ResponseCompleteCallback *responseCompleteCallback; 230 | void *callbackData; 231 | 232 | int aclXmlDocumentLen; 233 | char aclXmlDocument[ACL_XML_DOC_MAXSIZE]; 234 | int aclXmlDocumentBytesWritten; 235 | 236 | } SetAclData; 237 | 238 | 239 | static S3Status setAclPropertiesCallback 240 | (const S3ResponseProperties *responseProperties, void *callbackData) 241 | { 242 | SetAclData *paData = (SetAclData *) callbackData; 243 | 244 | return (*(paData->responsePropertiesCallback)) 245 | (responseProperties, paData->callbackData); 246 | } 247 | 248 | 249 | static int setAclDataCallback(int bufferSize, char *buffer, void *callbackData) 250 | { 251 | SetAclData *paData = (SetAclData *) callbackData; 252 | 253 | int remaining = (paData->aclXmlDocumentLen - 254 | paData->aclXmlDocumentBytesWritten); 255 | 256 | int toCopy = bufferSize > remaining ? remaining : bufferSize; 257 | 258 | if (!toCopy) { 259 | return 0; 260 | } 261 | 262 | memcpy(buffer, &(paData->aclXmlDocument 263 | [paData->aclXmlDocumentBytesWritten]), toCopy); 264 | 265 | paData->aclXmlDocumentBytesWritten += toCopy; 266 | 267 | return toCopy; 268 | } 269 | 270 | 271 | static void setAclCompleteCallback(S3Status requestStatus, 272 | const S3ErrorDetails *s3ErrorDetails, 273 | void *callbackData) 274 | { 275 | SetAclData *paData = (SetAclData *) callbackData; 276 | 277 | (*(paData->responseCompleteCallback)) 278 | (requestStatus, s3ErrorDetails, paData->callbackData); 279 | 280 | free(paData); 281 | } 282 | 283 | 284 | void S3_set_acl(const S3BucketContext *bucketContext, const char *key, 285 | const char *ownerId, const char *ownerDisplayName, 286 | int aclGrantCount, const S3AclGrant *aclGrants, 287 | S3RequestContext *requestContext, 288 | const S3ResponseHandler *handler, void *callbackData) 289 | { 290 | if (aclGrantCount > S3_MAX_ACL_GRANT_COUNT) { 291 | (*(handler->completeCallback)) 292 | (S3StatusTooManyGrants, 0, callbackData); 293 | return; 294 | } 295 | 296 | SetAclData *data = (SetAclData *) malloc(sizeof(SetAclData)); 297 | if (!data) { 298 | (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); 299 | return; 300 | } 301 | 302 | // Convert aclGrants to XML document 303 | S3Status status = generateAclXmlDocument 304 | (ownerId, ownerDisplayName, aclGrantCount, aclGrants, 305 | &(data->aclXmlDocumentLen), data->aclXmlDocument, 306 | sizeof(data->aclXmlDocument)); 307 | if (status != S3StatusOK) { 308 | free(data); 309 | (*(handler->completeCallback))(status, 0, callbackData); 310 | return; 311 | } 312 | 313 | data->responsePropertiesCallback = handler->propertiesCallback; 314 | data->responseCompleteCallback = handler->completeCallback; 315 | data->callbackData = callbackData; 316 | 317 | data->aclXmlDocumentBytesWritten = 0; 318 | 319 | // Set up the RequestParams 320 | RequestParams params = 321 | { 322 | HttpRequestTypePUT, // httpRequestType 323 | { bucketContext->hostName, // hostName 324 | bucketContext->bucketName, // bucketName 325 | bucketContext->protocol, // protocol 326 | bucketContext->uriStyle, // uriStyle 327 | bucketContext->accessKeyId, // accessKeyId 328 | bucketContext->secretAccessKey }, // secretAccessKey 329 | key, // key 330 | 0, // queryParams 331 | "acl", // subResource 332 | 0, // copySourceBucketName 333 | 0, // copySourceKey 334 | 0, // getConditions 335 | 0, // startByte 336 | 0, // byteCount 337 | 0, // putProperties 338 | &setAclPropertiesCallback, // propertiesCallback 339 | &setAclDataCallback, // toS3Callback 340 | data->aclXmlDocumentLen, // toS3CallbackTotalSize 341 | 0, // fromS3Callback 342 | &setAclCompleteCallback, // completeCallback 343 | data // callbackData 344 | }; 345 | 346 | // Perform the request 347 | request_perform(¶ms, requestContext); 348 | } 349 | -------------------------------------------------------------------------------- /GNUmakefile: -------------------------------------------------------------------------------- 1 | # GNUmakefile 2 | # 3 | # Copyright 2008 Bryan Ischo 4 | # 5 | # This file is part of libs3. 6 | # 7 | # libs3 is free software: you can redistribute it and/or modify it under the 8 | # terms of the GNU General Public License as published by the Free Software 9 | # Foundation, version 3 of the License. 10 | # 11 | # In addition, as a special exception, the copyright holders give 12 | # permission to link the code of this library and its programs with the 13 | # OpenSSL library, and distribute linked combinations including the two. 14 | # 15 | # libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 16 | # WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 17 | # FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 18 | # details. 19 | # 20 | # You should have received a copy of the GNU General Public License version 3 21 | # along with libs3, in a file named COPYING. If not, see 22 | # . 23 | 24 | # I tried to use the autoconf/automake/autolocal/etc (i.e. autohell) tools 25 | # but I just couldn't stomach them. Since this is a Makefile for POSIX 26 | # systems, I will simply do away with autohell completely and use a GNU 27 | # Makefile. GNU make ought to be available pretty much everywhere, so I 28 | # don't see this being a significant issue for portability. 29 | 30 | # All commands assume a GNU compiler. For systems which do not use a GNU 31 | # compiler, write scripts with the same names as these commands, and taking 32 | # the same arguments, and translate the arguments and commands into the 33 | # appropriate non-POSIX ones as needed. libs3 assumes a GNU toolchain as 34 | # the most portable way to build software possible. Non-POSIX, non-GNU 35 | # systems can do the work of supporting this build infrastructure. 36 | 37 | 38 | # -------------------------------------------------------------------------- 39 | # Set libs3 version number, unless it is already set. 40 | # This is trunk0.trunk0 on the libs3 git master branch; release branches 41 | # are created with this set to specific version numbers when releases are 42 | # made. 43 | 44 | LIBS3_VER_MAJOR ?= trunk0 45 | LIBS3_VER_MINOR ?= trunk0 46 | LIBS3_VER := $(LIBS3_VER_MAJOR).$(LIBS3_VER_MINOR) 47 | 48 | 49 | # ----------------------------------------------------------------------------- 50 | # Determine verbosity. VERBOSE_SHOW should be prepended to every command which 51 | # should only be displayed if VERBOSE is set. QUIET_ECHO may be used to 52 | # echo text only if VERBOSE is not set. Typically, a VERBOSE_SHOW command will 53 | # be paired with a QUIET_ECHO command, to provide a command which is displayed 54 | # in VERBOSE mode, along with text which is displayed in non-VERBOSE mode to 55 | # describe the command. 56 | # 57 | # No matter what VERBOSE is defined to, it ends up as true if it's defined. 58 | # This will be weird if you defined VERBOSE=false in the environment, and we 59 | # switch it to true here; but the meaning of VERBOSE is, "if it's defined to 60 | # any value, then verbosity is turned on". So don't define VERBOSE if you 61 | # don't want verbosity in the build process. 62 | # ----------------------------------------------------------------------------- 63 | 64 | ifdef VERBOSE 65 | VERBOSE = true 66 | VERBOSE_ECHO = @ echo 67 | VERBOSE_SHOW = 68 | QUIET_ECHO = @ echo > /dev/null 69 | else 70 | VERBOSE = false 71 | VERBOSE_ECHO = @ echo > /dev/null 72 | VERBOSE_SHOW = @ 73 | QUIET_ECHO = @ echo 74 | endif 75 | 76 | 77 | # -------------------------------------------------------------------------- 78 | # BUILD directory 79 | ifndef BUILD 80 | ifdef DEBUG 81 | BUILD := build-debug 82 | else 83 | BUILD := build 84 | endif 85 | endif 86 | 87 | 88 | # -------------------------------------------------------------------------- 89 | # DESTDIR directory 90 | ifndef DESTDIR 91 | DESTDIR := /usr 92 | endif 93 | 94 | # -------------------------------------------------------------------------- 95 | # Compiler CC handling 96 | ifndef CC 97 | CC := gcc 98 | endif 99 | 100 | # -------------------------------------------------------------------------- 101 | # Acquire configuration information for libraries that libs3 depends upon 102 | 103 | ifndef CURL_LIBS 104 | CURL_LIBS := $(shell curl-config --libs) 105 | endif 106 | 107 | ifndef CURL_CFLAGS 108 | CURL_CFLAGS := $(shell curl-config --cflags) 109 | endif 110 | 111 | ifndef LIBXML2_LIBS 112 | LIBXML2_LIBS := $(shell xml2-config --libs) 113 | endif 114 | 115 | ifndef LIBXML2_CFLAGS 116 | LIBXML2_CFLAGS := $(shell xml2-config --cflags) 117 | endif 118 | 119 | 120 | # -------------------------------------------------------------------------- 121 | # These CFLAGS assume a GNU compiler. For other compilers, write a script 122 | # which converts these arguments into their equivalent for that particular 123 | # compiler. 124 | 125 | ifndef CFLAGS 126 | ifdef DEBUG 127 | CFLAGS := -g 128 | else 129 | CFLAGS := -O3 130 | endif 131 | endif 132 | 133 | CFLAGS += -Wall -Werror -Wshadow -Wextra -Iinc \ 134 | $(CURL_CFLAGS) $(LIBXML2_CFLAGS) \ 135 | -DLIBS3_VER_MAJOR=\"$(LIBS3_VER_MAJOR)\" \ 136 | -DLIBS3_VER_MINOR=\"$(LIBS3_VER_MINOR)\" \ 137 | -DLIBS3_VER=\"$(LIBS3_VER)\" \ 138 | -D__STRICT_ANSI__ \ 139 | -D_ISOC99_SOURCE \ 140 | -D_POSIX_C_SOURCE=200112L 141 | 142 | LDFLAGS = $(CURL_LIBS) $(LIBXML2_LIBS) -lpthread 143 | 144 | 145 | # -------------------------------------------------------------------------- 146 | # Default targets are everything 147 | 148 | .PHONY: all 149 | all: exported test 150 | 151 | 152 | # -------------------------------------------------------------------------- 153 | # Exported targets are the library and driver program 154 | 155 | .PHONY: exported 156 | exported: libs3 s3 headers 157 | 158 | 159 | # -------------------------------------------------------------------------- 160 | # Install target 161 | 162 | # adding empty install target, don't want to install anything when integrated 163 | # with ceph 164 | .PHONY: install 165 | install: 166 | 167 | # this is the original install target 168 | .PHONY: install-all 169 | install-all: exported 170 | $(QUIET_ECHO) $(DESTDIR)/bin/s3: Installing executable 171 | $(VERBOSE_SHOW) install -Dps -m u+rwx,go+rx $(BUILD)/bin/s3 \ 172 | $(DESTDIR)/bin/s3 173 | $(QUIET_ECHO) \ 174 | $(DESTDIR)/lib/libs3.so.$(LIBS3_VER): Installing shared library 175 | $(VERBOSE_SHOW) install -Dps -m u+rw,go+r \ 176 | $(BUILD)/lib/libs3.so.$(LIBS3_VER_MAJOR) \ 177 | $(DESTDIR)/lib/libs3.so.$(LIBS3_VER) 178 | $(QUIET_ECHO) \ 179 | $(DESTDIR)/lib/libs3.so.$(LIBS3_VER_MAJOR): Linking shared library 180 | $(VERBOSE_SHOW) ln -sf libs3.so.$(LIBS3_VER) \ 181 | $(DESTDIR)/lib/libs3.so.$(LIBS3_VER_MAJOR) 182 | $(QUIET_ECHO) $(DESTDIR)/lib/libs3.so: Linking shared library 183 | $(VERBOSE_SHOW) ln -sf libs3.so.$(LIBS3_VER_MAJOR) $(DESTDIR)/lib/libs3.so 184 | $(QUIET_ECHO) $(DESTDIR)/lib/libs3.a: Installing static library 185 | $(VERBOSE_SHOW) install -Dp -m u+rw,go+r $(BUILD)/lib/libs3.a \ 186 | $(DESTDIR)/lib/libs3.a 187 | $(QUIET_ECHO) $(DESTDIR)/include/libs3.h: Installing header 188 | $(VERBOSE_SHOW) install -Dp -m u+rw,go+r $(BUILD)/include/libs3.h \ 189 | $(DESTDIR)/include/libs3.h 190 | 191 | 192 | # -------------------------------------------------------------------------- 193 | # Uninstall target 194 | 195 | .PHONY: uninstall 196 | uninstall: 197 | $(QUIET_ECHO) Installed files: Uninstalling 198 | $(VERBOSE_SHOW) \ 199 | rm -f $(DESTDIR)/bin/s3 \ 200 | $(DESTDIR)/include/libs3.h \ 201 | $(DESTDIR)/lib/libs3.a \ 202 | $(DESTDIR)/lib/libs3.so \ 203 | $(DESTDIR)/lib/libs3.so.$(LIBS3_VER_MAJOR) \ 204 | $(DESTDIR)/lib/libs3.so.$(LIBS3_VER) 205 | 206 | 207 | # -------------------------------------------------------------------------- 208 | # Compile target patterns 209 | 210 | $(BUILD)/obj/%.o: src/%.c 211 | $(QUIET_ECHO) $@: Compiling object 212 | @ mkdir -p $(dir $(BUILD)/dep/$<) 213 | @ $(CC) $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ 214 | -o $(BUILD)/dep/$(<:%.c=%.d) -c $< 215 | @ mkdir -p $(dir $@) 216 | $(VERBOSE_SHOW) $(CC) $(CFLAGS) -o $@ -c $< 217 | 218 | $(BUILD)/obj/%.do: src/%.c 219 | $(QUIET_ECHO) $@: Compiling dynamic object 220 | @ mkdir -p $(dir $(BUILD)/dep/$<) 221 | @ $(CC) $(CFLAGS) -M -MG -MQ $@ -DCOMPILINGDEPENDENCIES \ 222 | -o $(BUILD)/dep/$(<:%.c=%.dd) -c $< 223 | @ mkdir -p $(dir $@) 224 | $(VERBOSE_SHOW) $(CC) $(CFLAGS) -fpic -fPIC -o $@ -c $< 225 | 226 | 227 | # -------------------------------------------------------------------------- 228 | # libs3 library targets 229 | 230 | LIBS3_SHARED = $(BUILD)/lib/libs3.so.$(LIBS3_VER_MAJOR) 231 | LIBS3_STATIC = $(BUILD)/lib/libs3.a 232 | 233 | .PHONY: libs3 234 | libs3: $(LIBS3_SHARED) $(LIBS3_STATIC) 235 | 236 | LIBS3_SOURCES := acl.c bucket.c error_parser.c general.c \ 237 | object.c request.c request_context.c \ 238 | response_headers_handler.c service_access_logging.c \ 239 | service.c simplexml.c util.c 240 | 241 | $(LIBS3_SHARED): $(LIBS3_SOURCES:%.c=$(BUILD)/obj/%.do) 242 | $(QUIET_ECHO) $@: Building shared library 243 | @ mkdir -p $(dir $@) 244 | $(VERBOSE_SHOW) $(CC) -shared -Wl,-soname,libs3.so.$(LIBS3_VER_MAJOR) \ 245 | -o $@ $^ $(LDFLAGS) 246 | 247 | $(LIBS3_STATIC): $(LIBS3_SOURCES:%.c=$(BUILD)/obj/%.o) 248 | $(QUIET_ECHO) $@: Building static library 249 | @ mkdir -p $(dir $@) 250 | $(VERBOSE_SHOW) $(AR) cr $@ $^ 251 | 252 | 253 | # -------------------------------------------------------------------------- 254 | # Driver program targets 255 | 256 | .PHONY: s3 257 | s3: $(BUILD)/bin/s3 258 | 259 | $(BUILD)/bin/s3: $(BUILD)/obj/s3.o $(LIBS3_SHARED) 260 | $(QUIET_ECHO) $@: Building executable 261 | @ mkdir -p $(dir $@) 262 | $(VERBOSE_SHOW) $(CC) -o $@ $^ $(LDFLAGS) 263 | 264 | 265 | # -------------------------------------------------------------------------- 266 | # libs3 header targets 267 | 268 | .PHONY: headers 269 | headers: $(BUILD)/include/libs3.h 270 | 271 | $(BUILD)/include/libs3.h: inc/libs3.h 272 | $(QUIET_ECHO) $@: Linking header 273 | @ mkdir -p $(dir $@) 274 | $(VERBOSE_SHOW) ln -sf $(abspath $<) $@ 275 | 276 | 277 | # -------------------------------------------------------------------------- 278 | # Test targets 279 | 280 | .PHONY: test 281 | test: $(BUILD)/bin/testsimplexml 282 | 283 | $(BUILD)/bin/testsimplexml: $(BUILD)/obj/testsimplexml.o $(LIBS3_STATIC) 284 | $(QUIET_ECHO) $@: Building executable 285 | @ mkdir -p $(dir $@) 286 | $(VERBOSE_SHOW) $(CC) -o $@ $^ $(LIBXML2_LIBS) 287 | 288 | 289 | # -------------------------------------------------------------------------- 290 | # Check target 291 | 292 | check: 293 | distdir: 294 | dist: 295 | 296 | # -------------------------------------------------------------------------- 297 | # Clean target 298 | 299 | .PHONY: clean 300 | clean: 301 | $(QUIET_ECHO) $(BUILD): Cleaning 302 | $(VERBOSE_SHOW) rm -rf $(BUILD) 303 | 304 | .PHONY: distclean 305 | distclean: 306 | $(QUIET_ECHO) $(BUILD): Cleaning 307 | $(VERBOSE_SHOW) rm -rf $(BUILD) 308 | 309 | 310 | # -------------------------------------------------------------------------- 311 | # Clean dependencies target 312 | 313 | .PHONY: cleandeps 314 | cleandeps: 315 | $(QUIET_ECHO) $(BUILD)/dep: Cleaning dependencies 316 | $(VERBOSE_SHOW) rm -rf $(BUILD)/dep 317 | 318 | 319 | # -------------------------------------------------------------------------- 320 | # Dependencies 321 | 322 | ALL_SOURCES := $(LIBS3_SOURCES) s3.c testsimplexml.c 323 | 324 | $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.d))) 325 | $(foreach i, $(ALL_SOURCES), $(eval -include $(BUILD)/dep/src/$(i:%.c=%.dd))) 326 | 327 | 328 | # -------------------------------------------------------------------------- 329 | # Debian package target 330 | 331 | DEBPKG = $(BUILD)/pkg/libs3_$(LIBS3_VER).deb 332 | DEBDEVPKG = $(BUILD)/pkg/libs3-dev_$(LIBS3_VER).deb 333 | 334 | .PHONY: deb 335 | deb: $(DEBPKG) $(DEBDEVPKG) 336 | 337 | $(DEBPKG): DEBARCH = $(shell dpkg-architecture | grep ^DEB_BUILD_ARCH= | \ 338 | cut -d '=' -f 2) 339 | $(DEBPKG): exported $(BUILD)/deb/DEBIAN/control $(BUILD)/deb/DEBIAN/shlibs \ 340 | $(BUILD)/deb/DEBIAN/postinst \ 341 | $(BUILD)/deb/usr/share/doc/libs3/changelog.gz \ 342 | $(BUILD)/deb/usr/share/doc/libs3/changelog.Debian.gz \ 343 | $(BUILD)/deb/usr/share/doc/libs3/copyright 344 | DESTDIR=$(BUILD)/deb/usr $(MAKE) install 345 | rm -rf $(BUILD)/deb/usr/include 346 | rm -f $(BUILD)/deb/usr/lib/libs3.a 347 | @mkdir -p $(dir $@) 348 | fakeroot dpkg-deb -b $(BUILD)/deb $@ 349 | mv $@ $(BUILD)/pkg/libs3_$(LIBS3_VER)_$(DEBARCH).deb 350 | 351 | $(DEBDEVPKG): DEBARCH = $(shell dpkg-architecture | grep ^DEB_BUILD_ARCH= | \ 352 | cut -d '=' -f 2) 353 | $(DEBDEVPKG): exported $(BUILD)/deb-dev/DEBIAN/control \ 354 | $(BUILD)/deb-dev/usr/share/doc/libs3-dev/changelog.gz \ 355 | $(BUILD)/deb-dev/usr/share/doc/libs3-dev/changelog.Debian.gz \ 356 | $(BUILD)/deb-dev/usr/share/doc/libs3-dev/copyright 357 | DESTDIR=$(BUILD)/deb-dev/usr $(MAKE) install 358 | rm -rf $(BUILD)/deb-dev/usr/bin 359 | rm -f $(BUILD)/deb-dev/usr/lib/libs3.so* 360 | @mkdir -p $(dir $@) 361 | fakeroot dpkg-deb -b $(BUILD)/deb-dev $@ 362 | mv $@ $(BUILD)/pkg/libs3-dev_$(LIBS3_VER)_$(DEBARCH).deb 363 | 364 | $(BUILD)/deb/DEBIAN/control: debian/control 365 | @mkdir -p $(dir $@) 366 | echo -n "Depends: " > $@ 367 | dpkg-shlibdeps -Sbuild -O $(BUILD)/lib/libs3.so.$(LIBS3_VER_MAJOR) | \ 368 | cut -d '=' -f 2- >> $@ 369 | sed -e 's/LIBS3_VERSION/$(LIBS3_VER)/' \ 370 | < $< | sed -e 's/DEBIAN_ARCHITECTURE/$(DEBARCH)/' | \ 371 | grep -v ^Source: >> $@ 372 | 373 | $(BUILD)/deb-dev/DEBIAN/control: debian/control.dev 374 | @mkdir -p $(dir $@) 375 | sed -e 's/LIBS3_VERSION/$(LIBS3_VER)/' \ 376 | < $< | sed -e 's/DEBIAN_ARCHITECTURE/$(DEBARCH)/' > $@ 377 | 378 | $(BUILD)/deb/DEBIAN/shlibs: 379 | echo -n "libs3 $(LIBS3_VER_MAJOR) libs3 " > $@ 380 | echo "(>= $(LIBS3_VER))" >> $@ 381 | 382 | $(BUILD)/deb/DEBIAN/postinst: debian/postinst 383 | @mkdir -p $(dir $@) 384 | cp $< $@ 385 | 386 | $(BUILD)/deb/usr/share/doc/libs3/copyright: LICENSE 387 | @mkdir -p $(dir $@) 388 | cp $< $@ 389 | @echo >> $@ 390 | @echo -n "An alternate location for the GNU General Public " >> $@ 391 | @echo "License version 3 on Debian" >> $@ 392 | @echo "systems is /usr/share/common-licenses/GPL-3." >> $@ 393 | 394 | $(BUILD)/deb-dev/usr/share/doc/libs3-dev/copyright: LICENSE 395 | @mkdir -p $(dir $@) 396 | cp $< $@ 397 | @echo >> $@ 398 | @echo -n "An alternate location for the GNU General Public " >> $@ 399 | @echo "License version 3 on Debian" >> $@ 400 | @echo "systems is /usr/share/common-licenses/GPL-3." >> $@ 401 | 402 | $(BUILD)/deb/usr/share/doc/libs3/changelog.gz: debian/changelog 403 | @mkdir -p $(dir $@) 404 | gzip --best -c $< > $@ 405 | 406 | $(BUILD)/deb-dev/usr/share/doc/libs3-dev/changelog.gz: debian/changelog 407 | @mkdir -p $(dir $@) 408 | gzip --best -c $< > $@ 409 | 410 | $(BUILD)/deb/usr/share/doc/libs3/changelog.Debian.gz: debian/changelog.Debian 411 | @mkdir -p $(dir $@) 412 | gzip --best -c $< > $@ 413 | 414 | $(BUILD)/deb-dev/usr/share/doc/libs3-dev/changelog.Debian.gz: \ 415 | debian/changelog.Debian 416 | @mkdir -p $(dir $@) 417 | gzip --best -c $< > $@ 418 | 419 | 420 | -------------------------------------------------------------------------------- /src/object.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * object.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | #include "libs3.h" 30 | #include "request.h" 31 | 32 | 33 | // put object ---------------------------------------------------------------- 34 | 35 | void S3_put_object(const S3BucketContext *bucketContext, const char *key, 36 | uint64_t contentLength, 37 | const S3PutProperties *putProperties, 38 | S3RequestContext *requestContext, 39 | const S3PutObjectHandler *handler, void *callbackData) 40 | { 41 | // Set up the RequestParams 42 | RequestParams params = 43 | { 44 | HttpRequestTypePUT, // httpRequestType 45 | { bucketContext->hostName, // hostName 46 | bucketContext->bucketName, // bucketName 47 | bucketContext->protocol, // protocol 48 | bucketContext->uriStyle, // uriStyle 49 | bucketContext->accessKeyId, // accessKeyId 50 | bucketContext->secretAccessKey }, // secretAccessKey 51 | key, // key 52 | 0, // queryParams 53 | 0, // subResource 54 | 0, // copySourceBucketName 55 | 0, // copySourceKey 56 | 0, // getConditions 57 | 0, // startByte 58 | 0, // byteCount 59 | putProperties, // putProperties 60 | handler->responseHandler.propertiesCallback, // propertiesCallback 61 | handler->putObjectDataCallback, // toS3Callback 62 | contentLength, // toS3CallbackTotalSize 63 | 0, // fromS3Callback 64 | handler->responseHandler.completeCallback, // completeCallback 65 | callbackData // callbackData 66 | }; 67 | 68 | // Perform the request 69 | request_perform(¶ms, requestContext); 70 | } 71 | 72 | 73 | // copy object --------------------------------------------------------------- 74 | 75 | 76 | typedef struct CopyObjectData 77 | { 78 | SimpleXml simpleXml; 79 | 80 | S3ResponsePropertiesCallback *responsePropertiesCallback; 81 | S3ResponseCompleteCallback *responseCompleteCallback; 82 | void *callbackData; 83 | 84 | int64_t *lastModifiedReturn; 85 | int eTagReturnSize; 86 | char *eTagReturn; 87 | int eTagReturnLen; 88 | 89 | string_buffer(lastModified, 256); 90 | } CopyObjectData; 91 | 92 | 93 | static S3Status copyObjectXmlCallback(const char *elementPath, 94 | const char *data, int dataLen, 95 | void *callbackData) 96 | { 97 | CopyObjectData *coData = (CopyObjectData *) callbackData; 98 | 99 | int fit; 100 | 101 | if (data) { 102 | if (!strcmp(elementPath, "CopyObjectResult/LastModified")) { 103 | string_buffer_append(coData->lastModified, data, dataLen, fit); 104 | } 105 | else if (!strcmp(elementPath, "CopyObjectResult/ETag")) { 106 | if (coData->eTagReturnSize && coData->eTagReturn) { 107 | coData->eTagReturnLen += 108 | snprintf(&(coData->eTagReturn[coData->eTagReturnLen]), 109 | coData->eTagReturnSize - 110 | coData->eTagReturnLen - 1, 111 | "%.*s", dataLen, data); 112 | if (coData->eTagReturnLen >= coData->eTagReturnSize) { 113 | return S3StatusXmlParseFailure; 114 | } 115 | } 116 | } 117 | } 118 | 119 | /* Avoid compiler error about variable set but not used */ 120 | (void) fit; 121 | 122 | return S3StatusOK; 123 | } 124 | 125 | 126 | static S3Status copyObjectPropertiesCallback 127 | (const S3ResponseProperties *responseProperties, void *callbackData) 128 | { 129 | CopyObjectData *coData = (CopyObjectData *) callbackData; 130 | 131 | return (*(coData->responsePropertiesCallback)) 132 | (responseProperties, coData->callbackData); 133 | } 134 | 135 | 136 | static S3Status copyObjectDataCallback(int bufferSize, const char *buffer, 137 | void *callbackData) 138 | { 139 | CopyObjectData *coData = (CopyObjectData *) callbackData; 140 | 141 | return simplexml_add(&(coData->simpleXml), buffer, bufferSize); 142 | } 143 | 144 | 145 | static void copyObjectCompleteCallback(S3Status requestStatus, 146 | const S3ErrorDetails *s3ErrorDetails, 147 | void *callbackData) 148 | { 149 | CopyObjectData *coData = (CopyObjectData *) callbackData; 150 | 151 | if (coData->lastModifiedReturn) { 152 | time_t lastModified = -1; 153 | if (coData->lastModifiedLen) { 154 | lastModified = parseIso8601Time(coData->lastModified); 155 | } 156 | 157 | *(coData->lastModifiedReturn) = lastModified; 158 | } 159 | 160 | (*(coData->responseCompleteCallback)) 161 | (requestStatus, s3ErrorDetails, coData->callbackData); 162 | 163 | simplexml_deinitialize(&(coData->simpleXml)); 164 | 165 | free(coData); 166 | } 167 | 168 | 169 | void S3_copy_object(const S3BucketContext *bucketContext, const char *key, 170 | const char *destinationBucket, const char *destinationKey, 171 | const S3PutProperties *putProperties, 172 | int64_t *lastModifiedReturn, int eTagReturnSize, 173 | char *eTagReturn, S3RequestContext *requestContext, 174 | const S3ResponseHandler *handler, void *callbackData) 175 | { 176 | // Create the callback data 177 | CopyObjectData *data = 178 | (CopyObjectData *) malloc(sizeof(CopyObjectData)); 179 | if (!data) { 180 | (*(handler->completeCallback))(S3StatusOutOfMemory, 0, callbackData); 181 | return; 182 | } 183 | 184 | simplexml_initialize(&(data->simpleXml), ©ObjectXmlCallback, data); 185 | 186 | data->responsePropertiesCallback = handler->propertiesCallback; 187 | data->responseCompleteCallback = handler->completeCallback; 188 | data->callbackData = callbackData; 189 | 190 | data->lastModifiedReturn = lastModifiedReturn; 191 | data->eTagReturnSize = eTagReturnSize; 192 | data->eTagReturn = eTagReturn; 193 | if (data->eTagReturnSize && data->eTagReturn) { 194 | data->eTagReturn[0] = 0; 195 | } 196 | data->eTagReturnLen = 0; 197 | string_buffer_initialize(data->lastModified); 198 | 199 | // Set up the RequestParams 200 | RequestParams params = 201 | { 202 | HttpRequestTypeCOPY, // httpRequestType 203 | { bucketContext->hostName, // hostName 204 | destinationBucket ? destinationBucket : 205 | bucketContext->bucketName, // bucketName 206 | bucketContext->protocol, // protocol 207 | bucketContext->uriStyle, // uriStyle 208 | bucketContext->accessKeyId, // accessKeyId 209 | bucketContext->secretAccessKey }, // secretAccessKey 210 | destinationKey ? destinationKey : key, // key 211 | 0, // queryParams 212 | 0, // subResource 213 | bucketContext->bucketName, // copySourceBucketName 214 | key, // copySourceKey 215 | 0, // getConditions 216 | 0, // startByte 217 | 0, // byteCount 218 | putProperties, // putProperties 219 | ©ObjectPropertiesCallback, // propertiesCallback 220 | 0, // toS3Callback 221 | 0, // toS3CallbackTotalSize 222 | ©ObjectDataCallback, // fromS3Callback 223 | ©ObjectCompleteCallback, // completeCallback 224 | data // callbackData 225 | }; 226 | 227 | // Perform the request 228 | request_perform(¶ms, requestContext); 229 | } 230 | 231 | 232 | // get object ---------------------------------------------------------------- 233 | 234 | void S3_get_object(const S3BucketContext *bucketContext, const char *key, 235 | const S3GetConditions *getConditions, 236 | uint64_t startByte, uint64_t byteCount, 237 | S3RequestContext *requestContext, 238 | const S3GetObjectHandler *handler, void *callbackData) 239 | { 240 | // Set up the RequestParams 241 | RequestParams params = 242 | { 243 | HttpRequestTypeGET, // httpRequestType 244 | { bucketContext->hostName, // hostName 245 | bucketContext->bucketName, // bucketName 246 | bucketContext->protocol, // protocol 247 | bucketContext->uriStyle, // uriStyle 248 | bucketContext->accessKeyId, // accessKeyId 249 | bucketContext->secretAccessKey }, // secretAccessKey 250 | key, // key 251 | 0, // queryParams 252 | 0, // subResource 253 | 0, // copySourceBucketName 254 | 0, // copySourceKey 255 | getConditions, // getConditions 256 | startByte, // startByte 257 | byteCount, // byteCount 258 | 0, // putProperties 259 | handler->responseHandler.propertiesCallback, // propertiesCallback 260 | 0, // toS3Callback 261 | 0, // toS3CallbackTotalSize 262 | handler->getObjectDataCallback, // fromS3Callback 263 | handler->responseHandler.completeCallback, // completeCallback 264 | callbackData // callbackData 265 | }; 266 | 267 | // Perform the request 268 | request_perform(¶ms, requestContext); 269 | } 270 | 271 | 272 | // head object --------------------------------------------------------------- 273 | 274 | void S3_head_object(const S3BucketContext *bucketContext, const char *key, 275 | S3RequestContext *requestContext, 276 | const S3ResponseHandler *handler, void *callbackData) 277 | { 278 | // Set up the RequestParams 279 | RequestParams params = 280 | { 281 | HttpRequestTypeHEAD, // httpRequestType 282 | { bucketContext->hostName, // hostName 283 | bucketContext->bucketName, // bucketName 284 | bucketContext->protocol, // protocol 285 | bucketContext->uriStyle, // uriStyle 286 | bucketContext->accessKeyId, // accessKeyId 287 | bucketContext->secretAccessKey }, // secretAccessKey 288 | key, // key 289 | 0, // queryParams 290 | 0, // subResource 291 | 0, // copySourceBucketName 292 | 0, // copySourceKey 293 | 0, // getConditions 294 | 0, // startByte 295 | 0, // byteCount 296 | 0, // putProperties 297 | handler->propertiesCallback, // propertiesCallback 298 | 0, // toS3Callback 299 | 0, // toS3CallbackTotalSize 300 | 0, // fromS3Callback 301 | handler->completeCallback, // completeCallback 302 | callbackData // callbackData 303 | }; 304 | 305 | // Perform the request 306 | request_perform(¶ms, requestContext); 307 | } 308 | 309 | 310 | // delete object -------------------------------------------------------------- 311 | 312 | void S3_delete_object(const S3BucketContext *bucketContext, const char *key, 313 | S3RequestContext *requestContext, 314 | const S3ResponseHandler *handler, void *callbackData) 315 | { 316 | // Set up the RequestParams 317 | RequestParams params = 318 | { 319 | HttpRequestTypeDELETE, // httpRequestType 320 | { bucketContext->hostName, // hostName 321 | bucketContext->bucketName, // bucketName 322 | bucketContext->protocol, // protocol 323 | bucketContext->uriStyle, // uriStyle 324 | bucketContext->accessKeyId, // accessKeyId 325 | bucketContext->secretAccessKey }, // secretAccessKey 326 | key, // key 327 | 0, // queryParams 328 | 0, // subResource 329 | 0, // copySourceBucketName 330 | 0, // copySourceKey 331 | 0, // getConditions 332 | 0, // startByte 333 | 0, // byteCount 334 | 0, // putProperties 335 | handler->propertiesCallback, // propertiesCallback 336 | 0, // toS3Callback 337 | 0, // toS3CallbackTotalSize 338 | 0, // fromS3Callback 339 | handler->completeCallback, // completeCallback 340 | callbackData // callbackData 341 | }; 342 | 343 | // Perform the request 344 | request_perform(¶ms, requestContext); 345 | } 346 | -------------------------------------------------------------------------------- /src/util.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * util.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | #include "util.h" 30 | 31 | 32 | // Convenience utility for making the code look nicer. Tests a string 33 | // against a format; only the characters specified in the format are 34 | // checked (i.e. if the string is longer than the format, the string still 35 | // checks out ok). Format characters are: 36 | // d - is a digit 37 | // anything else - is that character 38 | // Returns nonzero the string checks out, zero if it does not. 39 | static int checkString(const char *str, const char *format) 40 | { 41 | while (*format) { 42 | if (*format == 'd') { 43 | if (!isdigit(*str)) { 44 | return 0; 45 | } 46 | } 47 | else if (*str != *format) { 48 | return 0; 49 | } 50 | str++, format++; 51 | } 52 | 53 | return 1; 54 | } 55 | 56 | 57 | int urlEncode(char *dest, const char *src, int maxSrcSize) 58 | { 59 | static const char *hex = "0123456789ABCDEF"; 60 | 61 | int len = 0; 62 | 63 | if (src) while (*src) { 64 | if (++len > maxSrcSize) { 65 | *dest = 0; 66 | return 0; 67 | } 68 | unsigned char c = *src; 69 | if (isalnum(c) || 70 | (c == '-') || (c == '_') || (c == '.') || (c == '!') || 71 | (c == '~') || (c == '*') || (c == '\'') || (c == '(') || 72 | (c == ')') || (c == '/')) { 73 | *dest++ = c; 74 | } 75 | else if (*src == ' ') { 76 | *dest++ = '+'; 77 | } 78 | else { 79 | *dest++ = '%'; 80 | *dest++ = hex[c >> 4]; 81 | *dest++ = hex[c & 15]; 82 | } 83 | src++; 84 | } 85 | 86 | *dest = 0; 87 | 88 | return 1; 89 | } 90 | 91 | 92 | int64_t parseIso8601Time(const char *str) 93 | { 94 | // Check to make sure that it has a valid format 95 | if (!checkString(str, "dddd-dd-ddTdd:dd:dd")) { 96 | return -1; 97 | } 98 | 99 | #define nextnum() (((*str - '0') * 10) + (*(str + 1) - '0')) 100 | 101 | // Convert it 102 | struct tm stm; 103 | memset(&stm, 0, sizeof(stm)); 104 | 105 | stm.tm_year = (nextnum() - 19) * 100; 106 | str += 2; 107 | stm.tm_year += nextnum(); 108 | str += 3; 109 | 110 | stm.tm_mon = nextnum() - 1; 111 | str += 3; 112 | 113 | stm.tm_mday = nextnum(); 114 | str += 3; 115 | 116 | stm.tm_hour = nextnum(); 117 | str += 3; 118 | 119 | stm.tm_min = nextnum(); 120 | str += 3; 121 | 122 | stm.tm_sec = nextnum(); 123 | str += 2; 124 | 125 | stm.tm_isdst = -1; 126 | 127 | int64_t ret = mktime(&stm); 128 | 129 | // Skip the millis 130 | 131 | if (*str == '.') { 132 | str++; 133 | while (isdigit(*str)) { 134 | str++; 135 | } 136 | } 137 | 138 | if (checkString(str, "-dd:dd") || checkString(str, "+dd:dd")) { 139 | int sign = (*str++ == '-') ? -1 : 1; 140 | int hours = nextnum(); 141 | str += 3; 142 | int minutes = nextnum(); 143 | ret += (-sign * (((hours * 60) + minutes) * 60)); 144 | } 145 | // Else it should be Z to be a conformant time string, but we just assume 146 | // that it is rather than enforcing that 147 | 148 | return ret; 149 | } 150 | 151 | 152 | uint64_t parseUnsignedInt(const char *str) 153 | { 154 | // Skip whitespace 155 | while (is_blank(*str)) { 156 | str++; 157 | } 158 | 159 | uint64_t ret = 0; 160 | 161 | while (isdigit(*str)) { 162 | ret *= 10; 163 | ret += (*str++ - '0'); 164 | } 165 | 166 | return ret; 167 | } 168 | 169 | 170 | int base64Encode(const unsigned char *in, int inLen, char *out) 171 | { 172 | static const char *ENC = 173 | "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"; 174 | 175 | char *original_out = out; 176 | 177 | while (inLen) { 178 | // first 6 bits of char 1 179 | *out++ = ENC[*in >> 2]; 180 | if (!--inLen) { 181 | // last 2 bits of char 1, 4 bits of 0 182 | *out++ = ENC[(*in & 0x3) << 4]; 183 | *out++ = '='; 184 | *out++ = '='; 185 | break; 186 | } 187 | // last 2 bits of char 1, first 4 bits of char 2 188 | *out++ = ENC[((*in & 0x3) << 4) | (*(in + 1) >> 4)]; 189 | in++; 190 | if (!--inLen) { 191 | // last 4 bits of char 2, 2 bits of 0 192 | *out++ = ENC[(*in & 0xF) << 2]; 193 | *out++ = '='; 194 | break; 195 | } 196 | // last 4 bits of char 2, first 2 bits of char 3 197 | *out++ = ENC[((*in & 0xF) << 2) | (*(in + 1) >> 6)]; 198 | in++; 199 | // last 6 bits of char 3 200 | *out++ = ENC[*in & 0x3F]; 201 | in++, inLen--; 202 | } 203 | 204 | return (out - original_out); 205 | } 206 | 207 | 208 | #define rol(value, bits) (((value) << (bits)) | ((value) >> (32 - (bits)))) 209 | 210 | #define blk0L(i) (block->l[i] = (rol(block->l[i], 24) & 0xFF00FF00) \ 211 | | (rol(block->l[i], 8) & 0x00FF00FF)) 212 | 213 | #define blk0B(i) (block->l[i]) 214 | 215 | #define blk(i) (block->l[i & 15] = rol(block->l[(i + 13) & 15] ^ \ 216 | block->l[(i + 8) & 15] ^ \ 217 | block->l[(i + 2) & 15] ^ \ 218 | block->l[i & 15], 1)) 219 | 220 | #define R0_L(v, w, x, y, z, i) \ 221 | z += ((w & (x ^ y)) ^ y) + blk0L(i) + 0x5A827999 + rol(v, 5); \ 222 | w = rol(w, 30); 223 | #define R0_B(v, w, x, y, z, i) \ 224 | z += ((w & (x ^ y)) ^ y) + blk0B(i) + 0x5A827999 + rol(v, 5); \ 225 | w = rol(w, 30); 226 | #define R1(v, w, x, y, z, i) \ 227 | z += ((w & (x ^ y)) ^ y) + blk(i) + 0x5A827999 + rol(v, 5); \ 228 | w = rol(w, 30); 229 | #define R2(v, w, x, y, z, i) \ 230 | z += (w ^ x ^ y) + blk(i) + 0x6ED9EBA1 + rol(v, 5); \ 231 | w = rol(w, 30); 232 | #define R3(v, w, x, y, z, i) \ 233 | z += (((w | x) & y) | (w & x)) + blk(i) + 0x8F1BBCDC + rol(v, 5); \ 234 | w = rol(w, 30); 235 | #define R4(v, w, x, y, z, i) \ 236 | z += (w ^ x ^ y) + blk(i) + 0xCA62C1D6 + rol(v, 5); \ 237 | w = rol(w, 30); 238 | 239 | #define R0A_L(i) R0_L(a, b, c, d, e, i) 240 | #define R0B_L(i) R0_L(b, c, d, e, a, i) 241 | #define R0C_L(i) R0_L(c, d, e, a, b, i) 242 | #define R0D_L(i) R0_L(d, e, a, b, c, i) 243 | #define R0E_L(i) R0_L(e, a, b, c, d, i) 244 | 245 | #define R0A_B(i) R0_B(a, b, c, d, e, i) 246 | #define R0B_B(i) R0_B(b, c, d, e, a, i) 247 | #define R0C_B(i) R0_B(c, d, e, a, b, i) 248 | #define R0D_B(i) R0_B(d, e, a, b, c, i) 249 | #define R0E_B(i) R0_B(e, a, b, c, d, i) 250 | 251 | #define R1A(i) R1(a, b, c, d, e, i) 252 | #define R1B(i) R1(b, c, d, e, a, i) 253 | #define R1C(i) R1(c, d, e, a, b, i) 254 | #define R1D(i) R1(d, e, a, b, c, i) 255 | #define R1E(i) R1(e, a, b, c, d, i) 256 | 257 | #define R2A(i) R2(a, b, c, d, e, i) 258 | #define R2B(i) R2(b, c, d, e, a, i) 259 | #define R2C(i) R2(c, d, e, a, b, i) 260 | #define R2D(i) R2(d, e, a, b, c, i) 261 | #define R2E(i) R2(e, a, b, c, d, i) 262 | 263 | #define R3A(i) R3(a, b, c, d, e, i) 264 | #define R3B(i) R3(b, c, d, e, a, i) 265 | #define R3C(i) R3(c, d, e, a, b, i) 266 | #define R3D(i) R3(d, e, a, b, c, i) 267 | #define R3E(i) R3(e, a, b, c, d, i) 268 | 269 | #define R4A(i) R4(a, b, c, d, e, i) 270 | #define R4B(i) R4(b, c, d, e, a, i) 271 | #define R4C(i) R4(c, d, e, a, b, i) 272 | #define R4D(i) R4(d, e, a, b, c, i) 273 | #define R4E(i) R4(e, a, b, c, d, i) 274 | 275 | 276 | static void SHA1_transform(uint32_t state[5], const unsigned char buffer[64]) 277 | { 278 | uint32_t a, b, c, d, e; 279 | 280 | typedef union { 281 | unsigned char c[64]; 282 | uint32_t l[16]; 283 | } u; 284 | 285 | unsigned char w[64]; 286 | u *block = (u *) w; 287 | 288 | memcpy(block, buffer, 64); 289 | 290 | a = state[0]; 291 | b = state[1]; 292 | c = state[2]; 293 | d = state[3]; 294 | e = state[4]; 295 | 296 | static uint32_t endianness_indicator = 0x1; 297 | if (((unsigned char *) &endianness_indicator)[0]) { 298 | R0A_L( 0); 299 | R0E_L( 1); R0D_L( 2); R0C_L( 3); R0B_L( 4); R0A_L( 5); 300 | R0E_L( 6); R0D_L( 7); R0C_L( 8); R0B_L( 9); R0A_L(10); 301 | R0E_L(11); R0D_L(12); R0C_L(13); R0B_L(14); R0A_L(15); 302 | } 303 | else { 304 | R0A_B( 0); 305 | R0E_B( 1); R0D_B( 2); R0C_B( 3); R0B_B( 4); R0A_B( 5); 306 | R0E_B( 6); R0D_B( 7); R0C_B( 8); R0B_B( 9); R0A_B(10); 307 | R0E_B(11); R0D_B(12); R0C_B(13); R0B_B(14); R0A_B(15); 308 | } 309 | R1E(16); R1D(17); R1C(18); R1B(19); R2A(20); 310 | R2E(21); R2D(22); R2C(23); R2B(24); R2A(25); 311 | R2E(26); R2D(27); R2C(28); R2B(29); R2A(30); 312 | R2E(31); R2D(32); R2C(33); R2B(34); R2A(35); 313 | R2E(36); R2D(37); R2C(38); R2B(39); R3A(40); 314 | R3E(41); R3D(42); R3C(43); R3B(44); R3A(45); 315 | R3E(46); R3D(47); R3C(48); R3B(49); R3A(50); 316 | R3E(51); R3D(52); R3C(53); R3B(54); R3A(55); 317 | R3E(56); R3D(57); R3C(58); R3B(59); R4A(60); 318 | R4E(61); R4D(62); R4C(63); R4B(64); R4A(65); 319 | R4E(66); R4D(67); R4C(68); R4B(69); R4A(70); 320 | R4E(71); R4D(72); R4C(73); R4B(74); R4A(75); 321 | R4E(76); R4D(77); R4C(78); R4B(79); 322 | 323 | state[0] += a; 324 | state[1] += b; 325 | state[2] += c; 326 | state[3] += d; 327 | state[4] += e; 328 | } 329 | 330 | 331 | typedef struct 332 | { 333 | uint32_t state[5]; 334 | uint32_t count[2]; 335 | unsigned char buffer[64]; 336 | } SHA1Context; 337 | 338 | 339 | static void SHA1_init(SHA1Context *context) 340 | { 341 | context->state[0] = 0x67452301; 342 | context->state[1] = 0xEFCDAB89; 343 | context->state[2] = 0x98BADCFE; 344 | context->state[3] = 0x10325476; 345 | context->state[4] = 0xC3D2E1F0; 346 | context->count[0] = context->count[1] = 0; 347 | } 348 | 349 | 350 | static void SHA1_update(SHA1Context *context, const unsigned char *data, 351 | unsigned int len) 352 | { 353 | uint32_t i, j; 354 | 355 | j = (context->count[0] >> 3) & 63; 356 | 357 | if ((context->count[0] += len << 3) < (len << 3)) { 358 | context->count[1]++; 359 | } 360 | 361 | context->count[1] += (len >> 29); 362 | 363 | if ((j + len) > 63) { 364 | memcpy(&(context->buffer[j]), data, (i = 64 - j)); 365 | SHA1_transform(context->state, context->buffer); 366 | for ( ; (i + 63) < len; i += 64) { 367 | SHA1_transform(context->state, &(data[i])); 368 | } 369 | j = 0; 370 | } 371 | else { 372 | i = 0; 373 | } 374 | 375 | memcpy(&(context->buffer[j]), &(data[i]), len - i); 376 | } 377 | 378 | 379 | static void SHA1_final(unsigned char digest[20], SHA1Context *context) 380 | { 381 | uint32_t i; 382 | unsigned char finalcount[8]; 383 | 384 | for (i = 0; i < 8; i++) { 385 | finalcount[i] = (unsigned char) 386 | ((context->count[(i >= 4 ? 0 : 1)] >> 387 | ((3 - (i & 3)) * 8)) & 255); 388 | } 389 | 390 | SHA1_update(context, (unsigned char *) "\200", 1); 391 | 392 | while ((context->count[0] & 504) != 448) { 393 | SHA1_update(context, (unsigned char *) "\0", 1); 394 | } 395 | 396 | SHA1_update(context, finalcount, 8); 397 | 398 | for (i = 0; i < 20; i++) { 399 | digest[i] = (unsigned char) 400 | ((context->state[i >> 2] >> ((3 - (i & 3)) * 8)) & 255); 401 | } 402 | 403 | memset(context->buffer, 0, 64); 404 | memset(context->state, 0, 20); 405 | memset(context->count, 0, 8); 406 | memset(&finalcount, 0, 8); 407 | 408 | SHA1_transform(context->state, context->buffer); 409 | } 410 | 411 | 412 | // HMAC-SHA-1: 413 | // 414 | // K - is key padded with zeros to 512 bits 415 | // m - is message 416 | // OPAD - 0x5c5c5c... 417 | // IPAD - 0x363636... 418 | // 419 | // HMAC(K,m) = SHA1((K ^ OPAD) . SHA1((K ^ IPAD) . m)) 420 | void HMAC_SHA1(unsigned char hmac[20], const unsigned char *key, int key_len, 421 | const unsigned char *message, int message_len) 422 | { 423 | unsigned char kopad[64], kipad[64]; 424 | int i; 425 | 426 | if (key_len > 64) { 427 | key_len = 64; 428 | } 429 | 430 | for (i = 0; i < key_len; i++) { 431 | kopad[i] = key[i] ^ 0x5c; 432 | kipad[i] = key[i] ^ 0x36; 433 | } 434 | 435 | for ( ; i < 64; i++) { 436 | kopad[i] = 0 ^ 0x5c; 437 | kipad[i] = 0 ^ 0x36; 438 | } 439 | 440 | unsigned char digest[20]; 441 | 442 | SHA1Context context; 443 | 444 | SHA1_init(&context); 445 | SHA1_update(&context, kipad, 64); 446 | SHA1_update(&context, message, message_len); 447 | SHA1_final(digest, &context); 448 | 449 | SHA1_init(&context); 450 | SHA1_update(&context, kopad, 64); 451 | SHA1_update(&context, digest, 20); 452 | SHA1_final(hmac, &context); 453 | } 454 | 455 | #define rot(x,k) (((x) << (k)) | ((x) >> (32 - (k)))) 456 | 457 | uint64_t hash(const unsigned char *k, int length) 458 | { 459 | uint32_t a, b, c; 460 | 461 | a = b = c = 0xdeadbeef + ((uint32_t) length); 462 | 463 | static uint32_t endianness_indicator = 0x1; 464 | if (((unsigned char *) &endianness_indicator)[0]) { 465 | while (length > 12) { 466 | a += k[0]; 467 | a += ((uint32_t) k[1]) << 8; 468 | a += ((uint32_t) k[2]) << 16; 469 | a += ((uint32_t) k[3]) << 24; 470 | b += k[4]; 471 | b += ((uint32_t) k[5]) << 8; 472 | b += ((uint32_t) k[6]) << 16; 473 | b += ((uint32_t) k[7]) << 24; 474 | c += k[8]; 475 | c += ((uint32_t) k[9]) << 8; 476 | c += ((uint32_t) k[10]) << 16; 477 | c += ((uint32_t) k[11]) << 24; 478 | a -= c; a ^= rot(c, 4); c += b; 479 | b -= a; b ^= rot(a, 6); a += c; 480 | c -= b; c ^= rot(b, 8); b += a; 481 | a -= c; a ^= rot(c, 16); c += b; 482 | b -= a; b ^= rot(a, 19); a += c; 483 | c -= b; c ^= rot(b, 4); b += a; 484 | length -= 12; 485 | k += 12; 486 | } 487 | 488 | switch(length) { 489 | case 12: c += ((uint32_t) k[11]) << 24; 490 | case 11: c += ((uint32_t) k[10]) << 16; 491 | case 10: c += ((uint32_t) k[9]) << 8; 492 | case 9 : c += k[8]; 493 | case 8 : b += ((uint32_t) k[7]) << 24; 494 | case 7 : b += ((uint32_t) k[6]) << 16; 495 | case 6 : b += ((uint32_t) k[5]) << 8; 496 | case 5 : b += k[4]; 497 | case 4 : a += ((uint32_t) k[3]) << 24; 498 | case 3 : a += ((uint32_t) k[2]) << 16; 499 | case 2 : a += ((uint32_t) k[1]) << 8; 500 | case 1 : a += k[0]; break; 501 | case 0 : goto end; 502 | } 503 | } 504 | else { 505 | while (length > 12) { 506 | a += ((uint32_t) k[0]) << 24; 507 | a += ((uint32_t) k[1]) << 16; 508 | a += ((uint32_t) k[2]) << 8; 509 | a += ((uint32_t) k[3]); 510 | b += ((uint32_t) k[4]) << 24; 511 | b += ((uint32_t) k[5]) << 16; 512 | b += ((uint32_t) k[6]) << 8; 513 | b += ((uint32_t) k[7]); 514 | c += ((uint32_t) k[8]) << 24; 515 | c += ((uint32_t) k[9]) << 16; 516 | c += ((uint32_t) k[10]) << 8; 517 | c += ((uint32_t) k[11]); 518 | a -= c; a ^= rot(c, 4); c += b; 519 | b -= a; b ^= rot(a, 6); a += c; 520 | c -= b; c ^= rot(b, 8); b += a; 521 | a -= c; a ^= rot(c, 16); c += b; 522 | b -= a; b ^= rot(a, 19); a += c; 523 | c -= b; c ^= rot(b, 4); b += a; 524 | length -= 12; 525 | k += 12; 526 | } 527 | 528 | switch(length) { 529 | case 12: c += k[11]; 530 | case 11: c += ((uint32_t) k[10]) << 8; 531 | case 10: c += ((uint32_t) k[9]) << 16; 532 | case 9 : c += ((uint32_t) k[8]) << 24; 533 | case 8 : b += k[7]; 534 | case 7 : b += ((uint32_t) k[6]) << 8; 535 | case 6 : b += ((uint32_t) k[5]) << 16; 536 | case 5 : b += ((uint32_t) k[4]) << 24; 537 | case 4 : a += k[3]; 538 | case 3 : a += ((uint32_t) k[2]) << 8; 539 | case 2 : a += ((uint32_t) k[1]) << 16; 540 | case 1 : a += ((uint32_t) k[0]) << 24; break; 541 | case 0 : goto end; 542 | } 543 | } 544 | 545 | c ^= b; c -= rot(b, 14); 546 | a ^= c; a -= rot(c, 11); 547 | b ^= a; b -= rot(a, 25); 548 | c ^= b; c -= rot(b, 16); 549 | a ^= c; a -= rot(c, 4); 550 | b ^= a; b -= rot(a, 14); 551 | c ^= b; c -= rot(b, 24); 552 | 553 | end: 554 | return ((((uint64_t) c) << 32) | b); 555 | } 556 | 557 | int is_blank(char c) 558 | { 559 | return ((c == ' ') || (c == '\t')); 560 | } 561 | -------------------------------------------------------------------------------- /src/general.c: -------------------------------------------------------------------------------- 1 | /** ************************************************************************** 2 | * general.c 3 | * 4 | * Copyright 2008 Bryan Ischo 5 | * 6 | * This file is part of libs3. 7 | * 8 | * libs3 is free software: you can redistribute it and/or modify it under the 9 | * terms of the GNU General Public License as published by the Free Software 10 | * Foundation, version 3 of the License. 11 | * 12 | * In addition, as a special exception, the copyright holders give 13 | * permission to link the code of this library and its programs with the 14 | * OpenSSL library, and distribute linked combinations including the two. 15 | * 16 | * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY 17 | * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS 18 | * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more 19 | * details. 20 | * 21 | * You should have received a copy of the GNU General Public License version 3 22 | * along with libs3, in a file named COPYING. If not, see 23 | * . 24 | * 25 | ************************************************************************** **/ 26 | 27 | #include 28 | #include 29 | #include "request.h" 30 | #include "simplexml.h" 31 | #include "util.h" 32 | 33 | static int initializeCountG = 0; 34 | 35 | S3Status S3_initialize(const char *userAgentInfo, int flags, 36 | const char *defaultS3HostName) 37 | { 38 | if (initializeCountG++) { 39 | return S3StatusOK; 40 | } 41 | 42 | return request_api_initialize(userAgentInfo, flags, defaultS3HostName); 43 | } 44 | 45 | 46 | void S3_deinitialize(void) 47 | { 48 | if (--initializeCountG) { 49 | return; 50 | } 51 | 52 | request_api_deinitialize(); 53 | } 54 | 55 | const char *S3_get_status_name(S3Status status) 56 | { 57 | switch (status) { 58 | #define handlecase(s) \ 59 | case S3Status##s: \ 60 | return #s 61 | 62 | handlecase(OK); 63 | handlecase(InternalError); 64 | handlecase(OutOfMemory); 65 | handlecase(Interrupted); 66 | handlecase(InvalidBucketNameTooLong); 67 | handlecase(InvalidBucketNameFirstCharacter); 68 | handlecase(InvalidBucketNameCharacter); 69 | handlecase(InvalidBucketNameCharacterSequence); 70 | handlecase(InvalidBucketNameTooShort); 71 | handlecase(InvalidBucketNameDotQuadNotation); 72 | handlecase(QueryParamsTooLong); 73 | handlecase(FailedToInitializeRequest); 74 | handlecase(MetaDataHeadersTooLong); 75 | handlecase(BadMetaData); 76 | handlecase(BadContentType); 77 | handlecase(ContentTypeTooLong); 78 | handlecase(BadMD5); 79 | handlecase(MD5TooLong); 80 | handlecase(BadCacheControl); 81 | handlecase(CacheControlTooLong); 82 | handlecase(BadContentDispositionFilename); 83 | handlecase(ContentDispositionFilenameTooLong); 84 | handlecase(BadContentEncoding); 85 | handlecase(ContentEncodingTooLong); 86 | handlecase(BadIfMatchETag); 87 | handlecase(IfMatchETagTooLong); 88 | handlecase(BadIfNotMatchETag); 89 | handlecase(IfNotMatchETagTooLong); 90 | handlecase(HeadersTooLong); 91 | handlecase(KeyTooLong); 92 | handlecase(UriTooLong); 93 | handlecase(XmlParseFailure); 94 | handlecase(EmailAddressTooLong); 95 | handlecase(UserIdTooLong); 96 | handlecase(UserDisplayNameTooLong); 97 | handlecase(GroupUriTooLong); 98 | handlecase(PermissionTooLong); 99 | handlecase(TargetBucketTooLong); 100 | handlecase(TargetPrefixTooLong); 101 | handlecase(TooManyGrants); 102 | handlecase(BadGrantee); 103 | handlecase(BadPermission); 104 | handlecase(XmlDocumentTooLarge); 105 | handlecase(NameLookupError); 106 | handlecase(FailedToConnect); 107 | handlecase(ServerFailedVerification); 108 | handlecase(ConnectionFailed); 109 | handlecase(AbortedByCallback); 110 | handlecase(ErrorAccessDenied); 111 | handlecase(ErrorAccountProblem); 112 | handlecase(ErrorAmbiguousGrantByEmailAddress); 113 | handlecase(ErrorBadDigest); 114 | handlecase(ErrorBucketAlreadyExists); 115 | handlecase(ErrorBucketAlreadyOwnedByYou); 116 | handlecase(ErrorBucketNotEmpty); 117 | handlecase(ErrorCredentialsNotSupported); 118 | handlecase(ErrorCrossLocationLoggingProhibited); 119 | handlecase(ErrorEntityTooSmall); 120 | handlecase(ErrorEntityTooLarge); 121 | handlecase(ErrorExpiredToken); 122 | handlecase(ErrorIncompleteBody); 123 | handlecase(ErrorIncorrectNumberOfFilesInPostRequest); 124 | handlecase(ErrorInlineDataTooLarge); 125 | handlecase(ErrorInternalError); 126 | handlecase(ErrorInvalidAccessKeyId); 127 | handlecase(ErrorInvalidAddressingHeader); 128 | handlecase(ErrorInvalidArgument); 129 | handlecase(ErrorInvalidBucketName); 130 | handlecase(ErrorInvalidDigest); 131 | handlecase(ErrorInvalidLocationConstraint); 132 | handlecase(ErrorInvalidPayer); 133 | handlecase(ErrorInvalidPolicyDocument); 134 | handlecase(ErrorInvalidRange); 135 | handlecase(ErrorInvalidSecurity); 136 | handlecase(ErrorInvalidSOAPRequest); 137 | handlecase(ErrorInvalidStorageClass); 138 | handlecase(ErrorInvalidTargetBucketForLogging); 139 | handlecase(ErrorInvalidToken); 140 | handlecase(ErrorInvalidURI); 141 | handlecase(ErrorKeyTooLong); 142 | handlecase(ErrorMalformedACLError); 143 | handlecase(ErrorMalformedXML); 144 | handlecase(ErrorMaxMessageLengthExceeded); 145 | handlecase(ErrorMaxPostPreDataLengthExceededError); 146 | handlecase(ErrorMetadataTooLarge); 147 | handlecase(ErrorMethodNotAllowed); 148 | handlecase(ErrorMissingAttachment); 149 | handlecase(ErrorMissingContentLength); 150 | handlecase(ErrorMissingSecurityElement); 151 | handlecase(ErrorMissingSecurityHeader); 152 | handlecase(ErrorNoLoggingStatusForKey); 153 | handlecase(ErrorNoSuchBucket); 154 | handlecase(ErrorNoSuchKey); 155 | handlecase(ErrorNotImplemented); 156 | handlecase(ErrorNotSignedUp); 157 | handlecase(ErrorOperationAborted); 158 | handlecase(ErrorPermanentRedirect); 159 | handlecase(ErrorPreconditionFailed); 160 | handlecase(ErrorRedirect); 161 | handlecase(ErrorRequestIsNotMultiPartContent); 162 | handlecase(ErrorRequestTimeout); 163 | handlecase(ErrorRequestTimeTooSkewed); 164 | handlecase(ErrorRequestTorrentOfBucketError); 165 | handlecase(ErrorSignatureDoesNotMatch); 166 | handlecase(ErrorSlowDown); 167 | handlecase(ErrorTemporaryRedirect); 168 | handlecase(ErrorTokenRefreshRequired); 169 | handlecase(ErrorTooManyBuckets); 170 | handlecase(ErrorUnexpectedContent); 171 | handlecase(ErrorUnresolvableGrantByEmailAddress); 172 | handlecase(ErrorUserKeyMustBeSpecified); 173 | handlecase(ErrorUnknown); 174 | handlecase(HttpErrorMovedTemporarily); 175 | handlecase(HttpErrorBadRequest); 176 | handlecase(HttpErrorForbidden); 177 | handlecase(HttpErrorNotFound); 178 | handlecase(HttpErrorConflict); 179 | handlecase(HttpErrorUnknown); 180 | } 181 | 182 | return "Unknown"; 183 | } 184 | 185 | 186 | S3Status S3_validate_bucket_name(const char *bucketName, S3UriStyle uriStyle) 187 | { 188 | int virtualHostStyle = (uriStyle == S3UriStyleVirtualHost); 189 | int len = 0, maxlen = virtualHostStyle ? 63 : 255; 190 | const char *b = bucketName; 191 | 192 | int hasDot = 0; 193 | int hasNonDigit = 0; 194 | 195 | while (*b) { 196 | if (len == maxlen) { 197 | return S3StatusInvalidBucketNameTooLong; 198 | } 199 | else if (isalpha(*b)) { 200 | len++, b++; 201 | hasNonDigit = 1; 202 | } 203 | else if (isdigit(*b)) { 204 | len++, b++; 205 | } 206 | else if (len == 0) { 207 | return S3StatusInvalidBucketNameFirstCharacter; 208 | } 209 | else if (*b == '_') { 210 | /* Virtual host style bucket names cannot have underscores */ 211 | if (virtualHostStyle) { 212 | return S3StatusInvalidBucketNameCharacter; 213 | } 214 | len++, b++; 215 | hasNonDigit = 1; 216 | } 217 | else if (*b == '-') { 218 | /* Virtual host style bucket names cannot have .- */ 219 | if (virtualHostStyle && (b > bucketName) && (*(b - 1) == '.')) { 220 | return S3StatusInvalidBucketNameCharacterSequence; 221 | } 222 | len++, b++; 223 | hasNonDigit = 1; 224 | } 225 | else if (*b == '.') { 226 | /* Virtual host style bucket names cannot have -. */ 227 | if (virtualHostStyle && (b > bucketName) && (*(b - 1) == '-')) { 228 | return S3StatusInvalidBucketNameCharacterSequence; 229 | } 230 | len++, b++; 231 | hasDot = 1; 232 | } 233 | else { 234 | return S3StatusInvalidBucketNameCharacter; 235 | } 236 | } 237 | 238 | if (len < 3) { 239 | return S3StatusInvalidBucketNameTooShort; 240 | } 241 | 242 | /* It's not clear from Amazon's documentation exactly what 'IP address 243 | style' means. In its strictest sense, it could mean 'could be a valid 244 | IP address', which would mean that 255.255.255.255 would be invalid, 245 | wherase 256.256.256.256 would be valid. Or it could mean 'has 4 sets 246 | of digits separated by dots'. Who knows. Let's just be really 247 | conservative here: if it has any dots, and no non-digit characters, 248 | then we reject it */ 249 | if (hasDot && !hasNonDigit) { 250 | return S3StatusInvalidBucketNameDotQuadNotation; 251 | } 252 | 253 | return S3StatusOK; 254 | } 255 | 256 | 257 | typedef struct ConvertAclData 258 | { 259 | char *ownerId; 260 | int ownerIdLen; 261 | char *ownerDisplayName; 262 | int ownerDisplayNameLen; 263 | int *aclGrantCountReturn; 264 | S3AclGrant *aclGrants; 265 | 266 | string_buffer(emailAddress, S3_MAX_GRANTEE_EMAIL_ADDRESS_SIZE); 267 | string_buffer(userId, S3_MAX_GRANTEE_USER_ID_SIZE); 268 | string_buffer(userDisplayName, S3_MAX_GRANTEE_DISPLAY_NAME_SIZE); 269 | string_buffer(groupUri, 128); 270 | string_buffer(permission, 32); 271 | } ConvertAclData; 272 | 273 | 274 | static S3Status convertAclXmlCallback(const char *elementPath, 275 | const char *data, int dataLen, 276 | void *callbackData) 277 | { 278 | ConvertAclData *caData = (ConvertAclData *) callbackData; 279 | 280 | int fit; 281 | 282 | if (data) { 283 | if (!strcmp(elementPath, "AccessControlPolicy/Owner/ID")) { 284 | caData->ownerIdLen += 285 | snprintf(&(caData->ownerId[caData->ownerIdLen]), 286 | S3_MAX_GRANTEE_USER_ID_SIZE - caData->ownerIdLen - 1, 287 | "%.*s", dataLen, data); 288 | if (caData->ownerIdLen >= S3_MAX_GRANTEE_USER_ID_SIZE) { 289 | return S3StatusUserIdTooLong; 290 | } 291 | } 292 | else if (!strcmp(elementPath, "AccessControlPolicy/Owner/" 293 | "DisplayName")) { 294 | caData->ownerDisplayNameLen += 295 | snprintf(&(caData->ownerDisplayName 296 | [caData->ownerDisplayNameLen]), 297 | S3_MAX_GRANTEE_DISPLAY_NAME_SIZE - 298 | caData->ownerDisplayNameLen - 1, 299 | "%.*s", dataLen, data); 300 | if (caData->ownerDisplayNameLen >= 301 | S3_MAX_GRANTEE_DISPLAY_NAME_SIZE) { 302 | return S3StatusUserDisplayNameTooLong; 303 | } 304 | } 305 | else if (!strcmp(elementPath, 306 | "AccessControlPolicy/AccessControlList/Grant/" 307 | "Grantee/EmailAddress")) { 308 | // AmazonCustomerByEmail 309 | string_buffer_append(caData->emailAddress, data, dataLen, fit); 310 | if (!fit) { 311 | return S3StatusEmailAddressTooLong; 312 | } 313 | } 314 | else if (!strcmp(elementPath, 315 | "AccessControlPolicy/AccessControlList/Grant/" 316 | "Grantee/ID")) { 317 | // CanonicalUser 318 | string_buffer_append(caData->userId, data, dataLen, fit); 319 | if (!fit) { 320 | return S3StatusUserIdTooLong; 321 | } 322 | } 323 | else if (!strcmp(elementPath, 324 | "AccessControlPolicy/AccessControlList/Grant/" 325 | "Grantee/DisplayName")) { 326 | // CanonicalUser 327 | string_buffer_append(caData->userDisplayName, data, dataLen, fit); 328 | if (!fit) { 329 | return S3StatusUserDisplayNameTooLong; 330 | } 331 | } 332 | else if (!strcmp(elementPath, 333 | "AccessControlPolicy/AccessControlList/Grant/" 334 | "Grantee/URI")) { 335 | // Group 336 | string_buffer_append(caData->groupUri, data, dataLen, fit); 337 | if (!fit) { 338 | return S3StatusGroupUriTooLong; 339 | } 340 | } 341 | else if (!strcmp(elementPath, 342 | "AccessControlPolicy/AccessControlList/Grant/" 343 | "Permission")) { 344 | // Permission 345 | string_buffer_append(caData->permission, data, dataLen, fit); 346 | if (!fit) { 347 | return S3StatusPermissionTooLong; 348 | } 349 | } 350 | } 351 | else { 352 | if (!strcmp(elementPath, "AccessControlPolicy/AccessControlList/" 353 | "Grant")) { 354 | // A grant has just been completed; so add the next S3AclGrant 355 | // based on the values read 356 | if (*(caData->aclGrantCountReturn) == S3_MAX_ACL_GRANT_COUNT) { 357 | return S3StatusTooManyGrants; 358 | } 359 | 360 | S3AclGrant *grant = &(caData->aclGrants 361 | [*(caData->aclGrantCountReturn)]); 362 | 363 | if (caData->emailAddress[0]) { 364 | grant->granteeType = S3GranteeTypeAmazonCustomerByEmail; 365 | strcpy(grant->grantee.amazonCustomerByEmail.emailAddress, 366 | caData->emailAddress); 367 | } 368 | else if (caData->userId[0] && caData->userDisplayName[0]) { 369 | grant->granteeType = S3GranteeTypeCanonicalUser; 370 | strcpy(grant->grantee.canonicalUser.id, caData->userId); 371 | strcpy(grant->grantee.canonicalUser.displayName, 372 | caData->userDisplayName); 373 | } 374 | else if (caData->groupUri[0]) { 375 | if (!strcmp(caData->groupUri, 376 | ACS_GROUP_AWS_USERS)) { 377 | grant->granteeType = S3GranteeTypeAllAwsUsers; 378 | } 379 | else if (!strcmp(caData->groupUri, 380 | ACS_GROUP_ALL_USERS)) { 381 | grant->granteeType = S3GranteeTypeAllUsers; 382 | } 383 | else if (!strcmp(caData->groupUri, 384 | ACS_GROUP_LOG_DELIVERY)) { 385 | grant->granteeType = S3GranteeTypeLogDelivery; 386 | } 387 | else { 388 | return S3StatusBadGrantee; 389 | } 390 | } 391 | else { 392 | return S3StatusBadGrantee; 393 | } 394 | 395 | if (!strcmp(caData->permission, "READ")) { 396 | grant->permission = S3PermissionRead; 397 | } 398 | else if (!strcmp(caData->permission, "WRITE")) { 399 | grant->permission = S3PermissionWrite; 400 | } 401 | else if (!strcmp(caData->permission, "READ_ACP")) { 402 | grant->permission = S3PermissionReadACP; 403 | } 404 | else if (!strcmp(caData->permission, "WRITE_ACP")) { 405 | grant->permission = S3PermissionWriteACP; 406 | } 407 | else if (!strcmp(caData->permission, "FULL_CONTROL")) { 408 | grant->permission = S3PermissionFullControl; 409 | } 410 | else { 411 | return S3StatusBadPermission; 412 | } 413 | 414 | (*(caData->aclGrantCountReturn))++; 415 | 416 | string_buffer_initialize(caData->emailAddress); 417 | string_buffer_initialize(caData->userId); 418 | string_buffer_initialize(caData->userDisplayName); 419 | string_buffer_initialize(caData->groupUri); 420 | string_buffer_initialize(caData->permission); 421 | } 422 | } 423 | 424 | return S3StatusOK; 425 | } 426 | 427 | 428 | S3Status S3_convert_acl(char *aclXml, char *ownerId, char *ownerDisplayName, 429 | int *aclGrantCountReturn, S3AclGrant *aclGrants) 430 | { 431 | ConvertAclData data; 432 | 433 | data.ownerId = ownerId; 434 | data.ownerIdLen = 0; 435 | data.ownerId[0] = 0; 436 | data.ownerDisplayName = ownerDisplayName; 437 | data.ownerDisplayNameLen = 0; 438 | data.ownerDisplayName[0] = 0; 439 | data.aclGrantCountReturn = aclGrantCountReturn; 440 | data.aclGrants = aclGrants; 441 | *aclGrantCountReturn = 0; 442 | string_buffer_initialize(data.emailAddress); 443 | string_buffer_initialize(data.userId); 444 | string_buffer_initialize(data.userDisplayName); 445 | string_buffer_initialize(data.groupUri); 446 | string_buffer_initialize(data.permission); 447 | 448 | // Use a simplexml parser 449 | SimpleXml simpleXml; 450 | simplexml_initialize(&simpleXml, &convertAclXmlCallback, &data); 451 | 452 | S3Status status = simplexml_add(&simpleXml, aclXml, strlen(aclXml)); 453 | 454 | simplexml_deinitialize(&simpleXml); 455 | 456 | return status; 457 | } 458 | 459 | 460 | int S3_status_is_retryable(S3Status status) 461 | { 462 | switch (status) { 463 | case S3StatusNameLookupError: 464 | case S3StatusFailedToConnect: 465 | case S3StatusConnectionFailed: 466 | case S3StatusErrorInternalError: 467 | case S3StatusErrorOperationAborted: 468 | case S3StatusErrorRequestTimeout: 469 | return 1; 470 | default: 471 | return 0; 472 | } 473 | } 474 | -------------------------------------------------------------------------------- /test/goodxml_03.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 4 | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 5 | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 6 | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 7 | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 8 | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 9 | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 10 | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 11 | 12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890 12 | 13 | 14 | --------------------------------------------------------------------------------