| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958195919601961196219631964196519661967196819691970197119721973197419751976197719781979198019811982198319841985198619871988198919901991199219931994199519961997199819992000200120022003200420052006200720082009201020112012201320142015201620172018201920202021202220232024202520262027202820292030203120322033203420352036203720382039204020412042204320442045204620472048204920502051205220532054205520562057205820592060206120622063206420652066206720682069207020712072207320742075207620772078207920802081208220832084208520862087208820892090209120922093209420952096209720982099210021012102210321042105210621072108210921102111211221132114211521162117211821192120212121222123212421252126212721282129213021312132213321342135213621372138213921402141214221432144214521462147214821492150215121522153215421552156215721582159216021612162216321642165216621672168216921702171217221732174217521762177217821792180218121822183218421852186218721882189219021912192219321942195219621972198219922002201220222032204220522062207220822092210221122122213221422152216221722182219222022212222222322242225222622272228222922302231223222332234223522362237223822392240224122422243224422452246224722482249225022512252225322542255225622572258225922602261226222632264226522662267226822692270227122722273227422752276227722782279228022812282228322842285228622872288228922902291229222932294229522962297229822992300230123022303230423052306230723082309231023112312231323142315231623172318231923202321232223232324232523262327232823292330233123322333233423352336233723382339234023412342234323442345234623472348234923502351235223532354235523562357235823592360236123622363236423652366236723682369237023712372237323742375237623772378237923802381238223832384238523862387238823892390239123922393239423952396239723982399240024012402240324042405240624072408240924102411241224132414241524162417241824192420242124222423242424252426242724282429243024312432243324342435243624372438243924402441244224432444244524462447244824492450245124522453245424552456245724582459246024612462246324642465246624672468246924702471247224732474247524762477247824792480248124822483248424852486248724882489249024912492249324942495249624972498249925002501250225032504250525062507250825092510251125122513251425152516251725182519252025212522252325242525252625272528252925302531253225332534253525362537253825392540254125422543254425452546254725482549255025512552255325542555255625572558255925602561256225632564256525662567256825692570257125722573257425752576257725782579258025812582258325842585258625872588258925902591259225932594259525962597259825992600260126022603260426052606260726082609261026112612261326142615261626172618261926202621262226232624262526262627262826292630263126322633263426352636263726382639264026412642264326442645264626472648264926502651265226532654265526562657265826592660266126622663266426652666266726682669267026712672267326742675267626772678267926802681268226832684268526862687268826892690269126922693269426952696269726982699270027012702270327042705270627072708270927102711271227132714271527162717271827192720272127222723272427252726272727282729273027312732273327342735273627372738273927402741274227432744274527462747274827492750275127522753275427552756275727582759276027612762276327642765276627672768276927702771277227732774277527762777277827792780278127822783278427852786278727882789279027912792279327942795279627972798279928002801280228032804280528062807280828092810281128122813281428152816281728182819282028212822282328242825282628272828282928302831283228332834283528362837283828392840284128422843284428452846284728482849285028512852285328542855285628572858285928602861286228632864286528662867286828692870287128722873287428752876287728782879288028812882288328842885288628872888288928902891289228932894289528962897289828992900290129022903290429052906290729082909291029112912291329142915291629172918291929202921292229232924292529262927292829292930293129322933293429352936293729382939294029412942294329442945294629472948294929502951295229532954295529562957295829592960296129622963296429652966296729682969297029712972297329742975297629772978297929802981298229832984298529862987298829892990299129922993299429952996299729982999300030013002300330043005300630073008300930103011301230133014301530163017301830193020302130223023302430253026302730283029303030313032303330343035303630373038303930403041304230433044304530463047304830493050305130523053305430553056305730583059306030613062306330643065306630673068306930703071307230733074307530763077307830793080308130823083308430853086308730883089309030913092309330943095309630973098309931003101310231033104310531063107310831093110311131123113311431153116311731183119312031213122312331243125312631273128312931303131313231333134313531363137313831393140314131423143314431453146314731483149315031513152315331543155315631573158315931603161316231633164316531663167316831693170317131723173317431753176317731783179318031813182318331843185318631873188318931903191319231933194319531963197319831993200320132023203320432053206320732083209321032113212321332143215321632173218321932203221322232233224322532263227322832293230323132323233323432353236323732383239324032413242324332443245324632473248324932503251325232533254325532563257325832593260326132623263326432653266326732683269327032713272327332743275327632773278327932803281328232833284328532863287328832893290329132923293329432953296329732983299330033013302330333043305330633073308330933103311331233133314331533163317331833193320332133223323332433253326332733283329333033313332333333343335333633373338333933403341334233433344334533463347334833493350335133523353335433553356335733583359336033613362336333643365336633673368336933703371337233733374337533763377337833793380338133823383338433853386338733883389339033913392339333943395339633973398339934003401340234033404340534063407340834093410341134123413341434153416341734183419342034213422342334243425342634273428342934303431343234333434343534363437343834393440344134423443344434453446344734483449345034513452345334543455345634573458345934603461346234633464346534663467346834693470347134723473347434753476347734783479348034813482348334843485348634873488348934903491349234933494349534963497349834993500350135023503350435053506350735083509351035113512351335143515351635173518351935203521352235233524352535263527352835293530353135323533353435353536353735383539354035413542354335443545354635473548354935503551355235533554355535563557355835593560356135623563356435653566356735683569357035713572357335743575357635773578357935803581358235833584358535863587358835893590359135923593359435953596359735983599360036013602360336043605360636073608360936103611361236133614361536163617361836193620362136223623362436253626362736283629363036313632363336343635363636373638363936403641364236433644364536463647364836493650365136523653365436553656365736583659366036613662366336643665366636673668366936703671367236733674367536763677367836793680368136823683368436853686368736883689369036913692369336943695369636973698369937003701370237033704370537063707370837093710371137123713371437153716371737183719372037213722372337243725372637273728372937303731373237333734373537363737373837393740374137423743374437453746374737483749375037513752375337543755375637573758375937603761376237633764376537663767376837693770377137723773377437753776377737783779378037813782378337843785378637873788378937903791379237933794379537963797379837993800380138023803380438053806380738083809381038113812381338143815381638173818381938203821382238233824382538263827382838293830383138323833383438353836383738383839384038413842384338443845384638473848384938503851385238533854385538563857385838593860386138623863386438653866386738683869387038713872387338743875387638773878387938803881388238833884388538863887388838893890389138923893389438953896389738983899390039013902390339043905390639073908390939103911391239133914391539163917391839193920392139223923392439253926392739283929393039313932393339343935393639373938393939403941394239433944394539463947394839493950395139523953395439553956395739583959396039613962396339643965396639673968396939703971397239733974397539763977397839793980398139823983398439853986398739883989399039913992399339943995399639973998399940004001400240034004400540064007400840094010401140124013401440154016401740184019402040214022402340244025402640274028402940304031403240334034403540364037403840394040 |
- /** **************************************************************************
- * s3.c
- *
- * Copyright 2008 Bryan Ischo <[email protected]>
- *
- * This file is part of libs3.
- *
- * libs3 is free software: you can redistribute it and/or modify it under the
- * terms of the GNU Lesser General Public License as published by the Free
- * Software Foundation, version 3 of the License.
- *
- * In addition, as a special exception, the copyright holders give
- * permission to link the code of this library and its programs with the
- * OpenSSL library, and distribute linked combinations including the two.
- *
- * libs3 is distributed in the hope that it will be useful, but WITHOUT ANY
- * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
- * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
- * details.
- *
- * You should have received a copy of the GNU Lesser General Public License
- * version 3 along with libs3, in a file named COPYING. If not, see
- * <https://www.gnu.org/licenses/>.
- *
- ************************************************************************** **/
- /**
- * This is a 'driver' program that simply converts command-line input into
- * calls to libs3 functions, and prints the results.
- **/
- #define _XOPEN_SOURCE 600
- #include <ctype.h>
- #include <getopt.h>
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- #include <strings.h>
- #include <sys/stat.h>
- #include <sys/types.h>
- #include <time.h>
- #include <unistd.h>
- #include "libs3.h"
- // Some Windows stuff
- #ifndef FOPEN_EXTRA_FLAGS
- #define FOPEN_EXTRA_FLAGS ""
- #endif
- // Some Unix stuff (to work around Windows issues)
- #ifndef SLEEP_UNITS_PER_SECOND
- #define SLEEP_UNITS_PER_SECOND 1
- #endif
- // Also needed for Windows, because somehow MinGW doesn't define this
- extern int putenv(char *);
- // Command-line options, saved as globals ------------------------------------
- static int forceG = 0;
- static int showResponsePropertiesG = 0;
- static S3Protocol protocolG = S3ProtocolHTTPS;
- static S3UriStyle uriStyleG = S3UriStylePath;
- static int retriesG = 5;
- static int timeoutMsG = 0;
- static int verifyPeerG = 0;
- static const char *awsRegionG = NULL;
- // Environment variables, saved as globals ----------------------------------
- static const char *accessKeyIdG = 0;
- static const char *secretAccessKeyG = 0;
- // Request results, saved as globals -----------------------------------------
- static int statusG = 0;
- static char errorDetailsG[4096] = { 0 };
- // Other globals -------------------------------------------------------------
- static char putenvBufG[256];
- // Option prefixes -----------------------------------------------------------
- #define LOCATION_PREFIX "location="
- #define LOCATION_PREFIX_LEN (sizeof(LOCATION_PREFIX) - 1)
- #define CANNED_ACL_PREFIX "cannedAcl="
- #define CANNED_ACL_PREFIX_LEN (sizeof(CANNED_ACL_PREFIX) - 1)
- #define PREFIX_PREFIX "prefix="
- #define PREFIX_PREFIX_LEN (sizeof(PREFIX_PREFIX) - 1)
- #define MARKER_PREFIX "marker="
- #define MARKER_PREFIX_LEN (sizeof(MARKER_PREFIX) - 1)
- #define DELIMITER_PREFIX "delimiter="
- #define DELIMITER_PREFIX_LEN (sizeof(DELIMITER_PREFIX) - 1)
- #define ENCODING_TYPE_PREFIX "encoding-type="
- #define ENCODING_TYPE_PREFIX_LEN (sizeof(ENCODING_TYPE_PREFIX) - 1)
- #define MAX_UPLOADS_PREFIX "max-uploads="
- #define MAX_UPLOADS_PREFIX_LEN (sizeof(MAX_UPLOADS_PREFIX) - 1)
- #define KEY_MARKER_PREFIX "key-marker="
- #define KEY_MARKER_PREFIX_LEN (sizeof(KEY_MARKER_PREFIX) - 1)
- #define UPLOAD_ID_PREFIX "upload-id="
- #define UPLOAD_ID_PREFIX_LEN (sizeof(UPLOAD_ID_PREFIX) - 1)
- #define MAX_PARTS_PREFIX "max-parts="
- #define MAX_PARTS_PREFIX_LEN (sizeof(MAX_PARTS_PREFIX) - 1)
- #define PART_NUMBER_MARKER_PREFIX "part-number-marker="
- #define PART_NUMBER_MARKER_PREFIX_LEN (sizeof(PART_NUMBER_MARKER_PREFIX) - 1)
- #define UPLOAD_ID_MARKER_PREFIX "upload-id-marker="
- #define UPLOAD_ID_MARKER_PREFIX_LEN (sizeof(UPLOAD_ID_MARKER_PREFIX) - 1)
- #define MAXKEYS_PREFIX "maxkeys="
- #define MAXKEYS_PREFIX_LEN (sizeof(MAXKEYS_PREFIX) - 1)
- #define FILENAME_PREFIX "filename="
- #define FILENAME_PREFIX_LEN (sizeof(FILENAME_PREFIX) - 1)
- #define CONTENT_LENGTH_PREFIX "contentLength="
- #define CONTENT_LENGTH_PREFIX_LEN (sizeof(CONTENT_LENGTH_PREFIX) - 1)
- #define CACHE_CONTROL_PREFIX "cacheControl="
- #define CACHE_CONTROL_PREFIX_LEN (sizeof(CACHE_CONTROL_PREFIX) - 1)
- #define CONTENT_TYPE_PREFIX "contentType="
- #define CONTENT_TYPE_PREFIX_LEN (sizeof(CONTENT_TYPE_PREFIX) - 1)
- #define MD5_PREFIX "md5="
- #define MD5_PREFIX_LEN (sizeof(MD5_PREFIX) - 1)
- #define CONTENT_DISPOSITION_FILENAME_PREFIX "contentDispositionFilename="
- #define CONTENT_DISPOSITION_FILENAME_PREFIX_LEN \
- (sizeof(CONTENT_DISPOSITION_FILENAME_PREFIX) - 1)
- #define CONTENT_ENCODING_PREFIX "contentEncoding="
- #define CONTENT_ENCODING_PREFIX_LEN (sizeof(CONTENT_ENCODING_PREFIX) - 1)
- #define EXPIRES_PREFIX "expires="
- #define EXPIRES_PREFIX_LEN (sizeof(EXPIRES_PREFIX) - 1)
- #define X_AMZ_META_PREFIX "x-amz-meta-"
- #define X_AMZ_META_PREFIX_LEN (sizeof(X_AMZ_META_PREFIX) - 1)
- #define USE_SERVER_SIDE_ENCRYPTION_PREFIX "useServerSideEncryption="
- #define USE_SERVER_SIDE_ENCRYPTION_PREFIX_LEN \
- (sizeof(USE_SERVER_SIDE_ENCRYPTION_PREFIX) - 1)
- #define IF_MODIFIED_SINCE_PREFIX "ifModifiedSince="
- #define IF_MODIFIED_SINCE_PREFIX_LEN (sizeof(IF_MODIFIED_SINCE_PREFIX) - 1)
- #define IF_NOT_MODIFIED_SINCE_PREFIX "ifNotmodifiedSince="
- #define IF_NOT_MODIFIED_SINCE_PREFIX_LEN \
- (sizeof(IF_NOT_MODIFIED_SINCE_PREFIX) - 1)
- #define IF_MATCH_PREFIX "ifMatch="
- #define IF_MATCH_PREFIX_LEN (sizeof(IF_MATCH_PREFIX) - 1)
- #define IF_NOT_MATCH_PREFIX "ifNotMatch="
- #define IF_NOT_MATCH_PREFIX_LEN (sizeof(IF_NOT_MATCH_PREFIX) - 1)
- #define START_BYTE_PREFIX "startByte="
- #define START_BYTE_PREFIX_LEN (sizeof(START_BYTE_PREFIX) - 1)
- #define BYTE_COUNT_PREFIX "byteCount="
- #define BYTE_COUNT_PREFIX_LEN (sizeof(BYTE_COUNT_PREFIX) - 1)
- #define ALL_DETAILS_PREFIX "allDetails="
- #define ALL_DETAILS_PREFIX_LEN (sizeof(ALL_DETAILS_PREFIX) - 1)
- #define NO_STATUS_PREFIX "noStatus="
- #define NO_STATUS_PREFIX_LEN (sizeof(NO_STATUS_PREFIX) - 1)
- #define RESOURCE_PREFIX "resource="
- #define RESOURCE_PREFIX_LEN (sizeof(RESOURCE_PREFIX) - 1)
- #define TARGET_BUCKET_PREFIX "targetBucket="
- #define TARGET_BUCKET_PREFIX_LEN (sizeof(TARGET_BUCKET_PREFIX) - 1)
- #define TARGET_PREFIX_PREFIX "targetPrefix="
- #define TARGET_PREFIX_PREFIX_LEN (sizeof(TARGET_PREFIX_PREFIX) - 1)
- #define HTTP_METHOD_PREFIX "method="
- #define HTTP_METHOD_PREFIX_LEN (sizeof(HTTP_METHOD_PREFIX) - 1)
- // util ----------------------------------------------------------------------
- static void S3_init()
- {
- S3Status status;
- const char *hostname = getenv("S3_HOSTNAME");
- if ((status = S3_initialize("s3", verifyPeerG|S3_INIT_ALL, hostname))
- != S3StatusOK) {
- fprintf(stderr, "Failed to initialize libs3: %s\n",
- S3_get_status_name(status));
- exit(-1);
- }
- }
- static void printError()
- {
- if (statusG < S3StatusErrorAccessDenied) {
- fprintf(stderr, "\nERROR: %s\n", S3_get_status_name(statusG));
- }
- else {
- fprintf(stderr, "\nERROR: %s\n", S3_get_status_name(statusG));
- fprintf(stderr, "%s\n", errorDetailsG);
- }
- }
- static void usageExit(FILE *out)
- {
- fprintf(out,
- "\n Options:\n"
- "\n"
- " Command Line:\n"
- "\n"
- " -f/--force : force operation despite warnings\n"
- " -h/--vhost-style : use virtual-host-style URIs (default is "
- "path-style)\n"
- " -u/--unencrypted : unencrypted (use HTTP instead of HTTPS)\n"
- " -s/--show-properties : show response properties on stdout\n"
- " -r/--retries : retry retryable failures this number of times\n"
- " (default is 5)\n"
- " -t/--timeout : request timeout, milliseconds. 0 if waiting forever\n"
- " (default is 0)\n"
- " -v/--verify-peer : verify peer SSL certificate (default is no)\n"
- " -g/--region <REGION> : use <REGION> for request authorization\n"
- "\n"
- " Environment:\n"
- "\n"
- " S3_ACCESS_KEY_ID : S3 access key ID (required)\n"
- " S3_SECRET_ACCESS_KEY : S3 secret access key (required)\n"
- " S3_HOSTNAME : specify alternative S3 host (optional)\n"
- "\n"
- " Commands (with <required parameters> and [optional parameters]) :\n"
- "\n"
- " (NOTE: all command parameters take a value and are specified using the\n"
- " pattern parameter=value)\n"
- "\n"
- " help : Prints this help text\n"
- "\n"
- " list : Lists owned buckets\n"
- " [allDetails] : Show full details\n"
- "\n"
- " test : Tests a bucket for existence and accessibility\n"
- " <bucket> : Bucket to test\n"
- "\n"
- " create : Create a new bucket\n"
- " <bucket> : Bucket to create\n"
- " [cannedAcl] : Canned ACL for the bucket (see Canned ACLs)\n"
- " [location] : Location for bucket (for example, EU)\n"
- "\n"
- " delete : Delete a bucket or key\n"
- " <bucket>[/<key>] : Bucket or bucket/key to delete\n"
- "\n"
- " list : List bucket contents\n"
- " <bucket> : Bucket to list\n"
- " [prefix] : Prefix for results set\n"
- " [marker] : Where in results set to start listing\n"
- " [delimiter] : Delimiter for rolling up results set\n"
- " [maxkeys] : Maximum number of keys to return in results set\n"
- " [allDetails] : Show full details for each key\n"
- "\n"
- " getacl : Get the ACL of a bucket or key\n"
- " <bucket>[/<key>] : Bucket or bucket/key to get the ACL of\n"
- " [filename] : Output filename for ACL (default is stdout)\n"
- "\n"
- " setacl : Set the ACL of a bucket or key\n"
- " <bucket>[/<key>] : Bucket or bucket/key to set the ACL of\n"
- " [filename] : Input filename for ACL (default is stdin)\n"
- " getlifecycle : Get the lifecycle of a bucket\n"
- " <bucket> : Bucket or bucket to get the lifecycle of\n"
- " [filename] : Output filename for lifecycle (default is stdout)\n"
- "\n"
- " setlifecycle : Set the lifecycle of a bucket or key\n"
- " <bucket> : Bucket or bucket to set the lifecycle of\n"
- " [filename] : Input filename for lifecycle (default is stdin)\n"
- "\n"
- " getlogging : Get the logging status of a bucket\n"
- " <bucket> : Bucket to get the logging status of\n"
- " [filename] : Output filename for logging (default is stdout)\n"
- "\n"
- " setlogging : Set the logging status of a bucket\n"
- " <bucket> : Bucket to set the logging status of\n"
- " [targetBucket] : Target bucket to log to; if not present, disables\n"
- " logging\n"
- " [targetPrefix] : Key prefix to use for logs\n"
- " [filename] : Input filename for logging (default is stdin)\n"
- "\n"
- " put : Puts an object\n"
- " <bucket>/<key> : Bucket/key to put object to\n"
- " [filename] : Filename to read source data from "
- "(default is stdin)\n"
- " [contentLength] : How many bytes of source data to put (required if\n"
- " source file is stdin)\n"
- " [cacheControl] : Cache-Control HTTP header string to associate with\n"
- " object\n"
- " [contentType] : Content-Type HTTP header string to associate with\n"
- " object\n"
- " [md5] : MD5 for validating source data\n"
- " [contentDispositionFilename] : Content-Disposition filename string to\n"
- " associate with object\n"
- " [contentEncoding] : Content-Encoding HTTP header string to associate\n"
- " with object\n"
- " [expires] : Expiration date to associate with object\n"
- " [cannedAcl] : Canned ACL for the object (see Canned ACLs)\n"
- " [x-amz-meta-...]] : Metadata headers to associate with the object\n"
- " [useServerSideEncryption] : Whether or not to use server-side\n"
- " encryption for the object\n"
- " [upload-id] : Upload-id of a uncomplete multipart upload, if you \n"
- " want to continue to put the object, you must specifil\n"
- "\n"
- " copy : Copies an object; if any options are set, the "
- "entire\n"
- " metadata of the object is replaced\n"
- " <sourcebucket>/<sourcekey> : Source bucket/key\n"
- " <destbucket>/<destkey> : Destination bucket/key\n"
- " [cacheControl] : Cache-Control HTTP header string to associate with\n"
- " object\n"
- " [contentType] : Content-Type HTTP header string to associate with\n"
- " object\n"
- " [contentDispositionFilename] : Content-Disposition filename string to\n"
- " associate with object\n"
- " [contentEncoding] : Content-Encoding HTTP header string to associate\n"
- " with object\n"
- " [expires] : Expiration date to associate with object\n"
- " [cannedAcl] : Canned ACL for the object (see Canned ACLs)\n"
- " [x-amz-meta-...]] : Metadata headers to associate with the object\n"
- "\n"
- " get : Gets an object\n"
- " <buckey>/<key> : Bucket/key of object to get\n"
- " [filename] : Filename to write object data to (required if -s\n"
- " command line parameter was used)\n"
- " [ifModifiedSince] : Only return the object if it has been modified "
- "since\n"
- " this date\n"
- " [ifNotmodifiedSince] : Only return the object if it has not been "
- "modified\n"
- " since this date\n"
- " [ifMatch] : Only return the object if its ETag header matches\n"
- " this string\n"
- " [ifNotMatch] : Only return the object if its ETag header does "
- "not\n"
- " match this string\n"
- " [startByte] : First byte of byte range to return\n"
- " [byteCount] : Number of bytes of byte range to return\n"
- "\n"
- " head : Gets only the headers of an object, implies -s\n"
- " <bucket>/<key> : Bucket/key of object to get headers of\n"
- "\n"
- " gqs : Generates an authenticated query string\n"
- " <bucket>[/<key>] : Bucket or bucket/key to generate query string for\n"
- " [expires] : Expiration date for query string\n"
- " [resource] : Sub-resource of key for query string, without a\n"
- " leading '?', for example, \"torrent\"\n"
- " [method] : HTTP method for use with the query string\n"
- " : (default is \"GET\")"
- "\n"
- " listmultiparts : Show multipart uploads\n"
- " <bucket> : Bucket multipart uploads belongs to\n"
- " [key-marker] : this parameter specifies the multipart upload after which listing should begin.\n"
- " [upload-id-marker] : Together with key-marker, specifies the multipart upload after which listing should begin\n"
- " [delimiter] : Character you use to group keys.\n"
- " [max-uploads] : Sets the maximum number of multipart uploads, from 1 to 1,000\n"
- " [encoding-type] : Requests Amazon S3 to encode the response and specifies the encoding method to use.\n"
- "\n"
- " abortmp : aborts a multipart upload.\n"
- " <bucket>/<key> : Bucket/key of upload belongs to.\n"
- " [upload-id] : upload-id of this upload\n"
- "\n"
- " listparts : lists the parts that have been uploaded for a specific multipart upload.\n"
- " <bucket>/<key> : Bucket/key of upload belongs to\n"
- " [upload-id] : upload-id of this upload\n"
- " [max-parts] : Sets the maximum number of parts to return in the response body.\n"
- " [encoding-type] : Requests Amazon S3 to encode the response and specifies the encoding method to use.\n"
- " [part-number-marker] : Specifies the part after which listing should begin.\n"
- "\n"
- " Canned ACLs:\n"
- "\n"
- " The following canned ACLs are supported:\n"
- " private (default), public-read, public-read-write, authenticated-read\n"
- "\n"
- " ACL Format:\n"
- "\n"
- " For the getacl and setacl commands, the format of the ACL list is:\n"
- " 1) An initial line giving the owner id in this format:\n"
- " OwnerID <Owner ID> <Owner Display Name>\n"
- " 2) Optional header lines, giving column headers, starting with the\n"
- " word \"Type\", or with some number of dashes\n"
- " 3) Grant lines, of the form:\n"
- " <Grant Type> (whitespace) <Grantee> (whitespace) <Permission>\n"
- " where Grant Type is one of: Email, UserID, or Group, and\n"
- " Grantee is the identification of the grantee based on this type,\n"
- " and Permission is one of: READ, WRITE, READ_ACP, or FULL_CONTROL.\n"
- "\n"
- " Note that the easiest way to modify an ACL is to first get it, saving it\n"
- " into a file, then modifying the file, and then setting the modified file\n"
- " back as the new ACL for the bucket/object.\n"
- "\n"
- " Date Format:\n"
- "\n"
- " The format for dates used in parameters is as ISO 8601 dates, i.e.\n"
- " YYYY-MM-DDTHH:MM:SS[+/-dd:dd]. Examples:\n"
- " 2008-07-29T20:36:14\n"
- " 2008-07-29T20:36:14-06:00\n"
- " 2008-07-29T20:36:14+11:30\n"
- "\n");
- exit(-1);
- }
- static uint64_t convertInt(const char *str, const char *paramName)
- {
- uint64_t ret = 0;
- while (*str) {
- if (!isdigit(*str)) {
- fprintf(stderr, "\nERROR: Nondigit in %s parameter: %c\n",
- paramName, *str);
- usageExit(stderr);
- }
- ret *= 10;
- ret += (*str++ - '0');
- }
- return ret;
- }
- typedef struct growbuffer
- {
- // The total number of bytes, and the start byte
- int size;
- // The start byte
- int start;
- // The blocks
- char data[64 * 1024];
- struct growbuffer *prev, *next;
- } growbuffer;
- // returns nonzero on success, zero on out of memory
- static int growbuffer_append(growbuffer **gb, const char *data, int dataLen)
- {
- int toCopy = 0 ;
- while (dataLen) {
- growbuffer *buf = *gb ? (*gb)->prev : 0;
- if (!buf || (buf->size == sizeof(buf->data))) {
- buf = (growbuffer *) malloc(sizeof(growbuffer));
- if (!buf) {
- return 0;
- }
- buf->size = 0;
- buf->start = 0;
- if (*gb && (*gb)->prev) {
- buf->prev = (*gb)->prev;
- buf->next = *gb;
- (*gb)->prev->next = buf;
- (*gb)->prev = buf;
- }
- else {
- buf->prev = buf->next = buf;
- *gb = buf;
- }
- }
- toCopy = (sizeof(buf->data) - buf->size);
- if (toCopy > dataLen) {
- toCopy = dataLen;
- }
- memcpy(&(buf->data[buf->size]), data, toCopy);
- buf->size += toCopy, data += toCopy, dataLen -= toCopy;
- }
- return toCopy;
- }
- static void growbuffer_read(growbuffer **gb, int amt, int *amtReturn,
- char *buffer)
- {
- *amtReturn = 0;
- growbuffer *buf = *gb;
- if (!buf) {
- return;
- }
- *amtReturn = (buf->size > amt) ? amt : buf->size;
- memcpy(buffer, &(buf->data[buf->start]), *amtReturn);
- buf->start += *amtReturn, buf->size -= *amtReturn;
- if (buf->size == 0) {
- if (buf->next == buf) {
- *gb = 0;
- }
- else {
- *gb = buf->next;
- buf->prev->next = buf->next;
- buf->next->prev = buf->prev;
- }
- free(buf);
- }
- }
- static void growbuffer_destroy(growbuffer *gb)
- {
- growbuffer *start = gb;
- while (gb) {
- growbuffer *next = gb->next;
- free(gb);
- gb = (next == start) ? 0 : next;
- }
- }
- // Convenience utility for making the code look nicer. Tests a string
- // against a format; only the characters specified in the format are
- // checked (i.e. if the string is longer than the format, the string still
- // checks out ok). Format characters are:
- // d - is a digit
- // anything else - is that character
- // Returns nonzero the string checks out, zero if it does not.
- static int checkString(const char *str, const char *format)
- {
- while (*format) {
- if (*format == 'd') {
- if (!isdigit(*str)) {
- return 0;
- }
- }
- else if (*str != *format) {
- return 0;
- }
- str++, format++;
- }
- return 1;
- }
- static int64_t parseIso8601Time(const char *str)
- {
- // Check to make sure that it has a valid format
- if (!checkString(str, "dddd-dd-ddTdd:dd:dd")) {
- return -1;
- }
- #define nextnum() (((*str - '0') * 10) + (*(str + 1) - '0'))
- // Convert it
- struct tm stm;
- memset(&stm, 0, sizeof(stm));
- stm.tm_year = (nextnum() - 19) * 100;
- str += 2;
- stm.tm_year += nextnum();
- str += 3;
- stm.tm_mon = nextnum() - 1;
- str += 3;
- stm.tm_mday = nextnum();
- str += 3;
- stm.tm_hour = nextnum();
- str += 3;
- stm.tm_min = nextnum();
- str += 3;
- stm.tm_sec = nextnum();
- str += 2;
- stm.tm_isdst = -1;
- // This is hokey but it's the recommended way ...
- char *tz = getenv("TZ");
- snprintf(putenvBufG, sizeof(putenvBufG), "TZ=UTC");
- putenv(putenvBufG);
- int64_t ret = mktime(&stm);
- snprintf(putenvBufG, sizeof(putenvBufG), "TZ=%s", tz ? tz : "");
- putenv(putenvBufG);
- // Skip the millis
- if (*str == '.') {
- str++;
- while (isdigit(*str)) {
- str++;
- }
- }
- if (checkString(str, "-dd:dd") || checkString(str, "+dd:dd")) {
- int sign = (*str++ == '-') ? -1 : 1;
- int hours = nextnum();
- str += 3;
- int minutes = nextnum();
- ret += (-sign * (((hours * 60) + minutes) * 60));
- }
- // Else it should be Z to be a conformant time string, but we just assume
- // that it is rather than enforcing that
- return ret;
- }
- // Simple ACL format: Lines of this format:
- // Type - ignored
- // Starting with a dash - ignored
- // Email email_address permission
- // UserID user_id (display_name) permission
- // Group Authenticated AWS Users permission
- // Group All Users permission
- // permission is one of READ, WRITE, READ_ACP, WRITE_ACP, FULL_CONTROL
- static int convert_simple_acl(char *aclXml, char *ownerId,
- char *ownerDisplayName,
- int *aclGrantCountReturn,
- S3AclGrant *aclGrants)
- {
- *aclGrantCountReturn = 0;
- *ownerId = 0;
- *ownerDisplayName = 0;
- #define SKIP_SPACE(require_more) \
- do { \
- while (isspace(*aclXml)) { \
- aclXml++; \
- } \
- if (require_more && !*aclXml) { \
- return 0; \
- } \
- } while (0)
- #define COPY_STRING_MAXLEN(field, maxlen) \
- do { \
- SKIP_SPACE(1); \
- int len = 0; \
- while ((len < maxlen) && !isspace(*aclXml)) { \
- field[len++] = *aclXml++; \
- } \
- field[len] = 0; \
- } while (0)
- #define COPY_STRING(field) \
- COPY_STRING_MAXLEN(field, (int) (sizeof(field) - 1))
- while (1) {
- SKIP_SPACE(0);
- if (!*aclXml) {
- break;
- }
- // Skip Type lines and dash lines
- if (!strncmp(aclXml, "Type", sizeof("Type") - 1) ||
- (*aclXml == '-')) {
- while (*aclXml && ((*aclXml != '\n') && (*aclXml != '\r'))) {
- aclXml++;
- }
- continue;
- }
- if (!strncmp(aclXml, "OwnerID", sizeof("OwnerID") - 1)) {
- aclXml += sizeof("OwnerID") - 1;
- COPY_STRING_MAXLEN(ownerId, S3_MAX_GRANTEE_USER_ID_SIZE);
- SKIP_SPACE(1);
- COPY_STRING_MAXLEN(ownerDisplayName,
- S3_MAX_GRANTEE_DISPLAY_NAME_SIZE);
- continue;
- }
- if (*aclGrantCountReturn == S3_MAX_ACL_GRANT_COUNT) {
- return 0;
- }
- S3AclGrant *grant = &(aclGrants[(*aclGrantCountReturn)++]);
- if (!strncmp(aclXml, "Email", sizeof("Email") - 1)) {
- grant->granteeType = S3GranteeTypeAmazonCustomerByEmail;
- aclXml += sizeof("Email") - 1;
- COPY_STRING(grant->grantee.amazonCustomerByEmail.emailAddress);
- }
- else if (!strncmp(aclXml, "UserID", sizeof("UserID") - 1)) {
- grant->granteeType = S3GranteeTypeCanonicalUser;
- aclXml += sizeof("UserID") - 1;
- COPY_STRING(grant->grantee.canonicalUser.id);
- SKIP_SPACE(1);
- // Now do display name
- COPY_STRING(grant->grantee.canonicalUser.displayName);
- }
- else if (!strncmp(aclXml, "Group", sizeof("Group") - 1)) {
- aclXml += sizeof("Group") - 1;
- SKIP_SPACE(1);
- if (!strncmp(aclXml, "Authenticated AWS Users",
- sizeof("Authenticated AWS Users") - 1)) {
- grant->granteeType = S3GranteeTypeAllAwsUsers;
- aclXml += (sizeof("Authenticated AWS Users") - 1);
- }
- else if (!strncmp(aclXml, "All Users", sizeof("All Users") - 1)) {
- grant->granteeType = S3GranteeTypeAllUsers;
- aclXml += (sizeof("All Users") - 1);
- }
- else if (!strncmp(aclXml, "Log Delivery",
- sizeof("Log Delivery") - 1)) {
- grant->granteeType = S3GranteeTypeLogDelivery;
- aclXml += (sizeof("Log Delivery") - 1);
- }
- else {
- return 0;
- }
- }
- else {
- return 0;
- }
- SKIP_SPACE(1);
- if (!strncmp(aclXml, "READ_ACP", sizeof("READ_ACP") - 1)) {
- grant->permission = S3PermissionReadACP;
- aclXml += (sizeof("READ_ACP") - 1);
- }
- else if (!strncmp(aclXml, "READ", sizeof("READ") - 1)) {
- grant->permission = S3PermissionRead;
- aclXml += (sizeof("READ") - 1);
- }
- else if (!strncmp(aclXml, "WRITE_ACP", sizeof("WRITE_ACP") - 1)) {
- grant->permission = S3PermissionWriteACP;
- aclXml += (sizeof("WRITE_ACP") - 1);
- }
- else if (!strncmp(aclXml, "WRITE", sizeof("WRITE") - 1)) {
- grant->permission = S3PermissionWrite;
- aclXml += (sizeof("WRITE") - 1);
- }
- else if (!strncmp(aclXml, "FULL_CONTROL",
- sizeof("FULL_CONTROL") - 1)) {
- grant->permission = S3PermissionFullControl;
- aclXml += (sizeof("FULL_CONTROL") - 1);
- }
- }
- return 1;
- }
- static int should_retry()
- {
- if (retriesG--) {
- // Sleep before next retry; start out with a 1 second sleep
- static int retrySleepInterval = 1 * SLEEP_UNITS_PER_SECOND;
- sleep(retrySleepInterval);
- // Next sleep 1 second longer
- retrySleepInterval++;
- return 1;
- }
- return 0;
- }
- static struct option longOptionsG[] =
- {
- { "force", no_argument, 0, 'f' },
- { "vhost-style", no_argument, 0, 'h' },
- { "unencrypted", no_argument, 0, 'u' },
- { "show-properties", no_argument, 0, 's' },
- { "retries", required_argument, 0, 'r' },
- { "timeout", required_argument, 0, 't' },
- { "verify-peer", no_argument, 0, 'v' },
- { "region", required_argument, 0, 'g' },
- { 0, 0, 0, 0 }
- };
- // response properties callback ----------------------------------------------
- // This callback does the same thing for every request type: prints out the
- // properties if the user has requested them to be so
- static S3Status responsePropertiesCallback
- (const S3ResponseProperties *properties, void *callbackData)
- {
- (void) callbackData;
- if (!showResponsePropertiesG) {
- return S3StatusOK;
- }
- #define print_nonnull(name, field) \
- do { \
- if (properties-> field) { \
- printf("%s: %s\n", name, properties-> field); \
- } \
- } while (0)
- print_nonnull("Content-Type", contentType);
- print_nonnull("Request-Id", requestId);
- print_nonnull("Request-Id-2", requestId2);
- if (properties->contentLength > 0) {
- printf("Content-Length: %llu\n",
- (unsigned long long) properties->contentLength);
- }
- print_nonnull("Server", server);
- print_nonnull("ETag", eTag);
- if (properties->lastModified > 0) {
- char timebuf[256];
- time_t t = (time_t) properties->lastModified;
- // gmtime is not thread-safe but we don't care here.
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t));
- printf("Last-Modified: %s\n", timebuf);
- }
- int i;
- for (i = 0; i < properties->metaDataCount; i++) {
- printf("x-amz-meta-%s: %s\n", properties->metaData[i].name,
- properties->metaData[i].value);
- }
- if (properties->usesServerSideEncryption) {
- printf("UsesServerSideEncryption: true\n");
- }
- return S3StatusOK;
- }
- // response complete callback ------------------------------------------------
- // This callback does the same thing for every request type: saves the status
- // and error stuff in global variables
- static void responseCompleteCallback(S3Status status,
- const S3ErrorDetails *error,
- void *callbackData)
- {
- (void) callbackData;
- statusG = status;
- // Compose the error details message now, although we might not use it.
- // Can't just save a pointer to [error] since it's not guaranteed to last
- // beyond this callback
- int len = 0;
- if (error && error->message) {
- len += snprintf(&(errorDetailsG[len]), sizeof(errorDetailsG) - len,
- " Message: %s\n", error->message);
- }
- if (error && error->resource) {
- len += snprintf(&(errorDetailsG[len]), sizeof(errorDetailsG) - len,
- " Resource: %s\n", error->resource);
- }
- if (error && error->furtherDetails) {
- len += snprintf(&(errorDetailsG[len]), sizeof(errorDetailsG) - len,
- " Further Details: %s\n", error->furtherDetails);
- }
- if (error && error->extraDetailsCount) {
- len += snprintf(&(errorDetailsG[len]), sizeof(errorDetailsG) - len,
- "%s", " Extra Details:\n");
- int i;
- for (i = 0; i < error->extraDetailsCount; i++) {
- len += snprintf(&(errorDetailsG[len]),
- sizeof(errorDetailsG) - len, " %s: %s\n",
- error->extraDetails[i].name,
- error->extraDetails[i].value);
- }
- }
- }
- // list service --------------------------------------------------------------
- typedef struct list_service_data
- {
- int headerPrinted;
- int allDetails;
- } list_service_data;
- static void printListServiceHeader(int allDetails)
- {
- printf("%-56s %-20s", " Bucket",
- " Created");
- if (allDetails) {
- printf(" %-64s %-12s",
- " Owner ID",
- "Display Name");
- }
- printf("\n");
- printf("-------------------------------------------------------- "
- "--------------------");
- if (allDetails) {
- printf(" -------------------------------------------------"
- "--------------- ------------");
- }
- printf("\n");
- }
- static S3Status listServiceCallback(const char *ownerId,
- const char *ownerDisplayName,
- const char *bucketName,
- int64_t creationDate, void *callbackData)
- {
- list_service_data *data = (list_service_data *) callbackData;
- if (!data->headerPrinted) {
- data->headerPrinted = 1;
- printListServiceHeader(data->allDetails);
- }
- char timebuf[256];
- if (creationDate >= 0) {
- time_t t = (time_t) creationDate;
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ", gmtime(&t));
- }
- else {
- timebuf[0] = 0;
- }
- printf("%-56s %-20s", bucketName, timebuf);
- if (data->allDetails) {
- printf(" %-64s %-12s", ownerId ? ownerId : "",
- ownerDisplayName ? ownerDisplayName : "");
- }
- printf("\n");
- return S3StatusOK;
- }
- static void list_service(int allDetails)
- {
- list_service_data data;
- data.headerPrinted = 0;
- data.allDetails = allDetails;
- S3_init();
- S3ListServiceHandler listServiceHandler =
- {
- { &responsePropertiesCallback, &responseCompleteCallback },
- &listServiceCallback
- };
- do {
- S3_list_service(protocolG, accessKeyIdG, secretAccessKeyG, 0, 0,
- awsRegionG, 0, timeoutMsG, &listServiceHandler, &data);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG == S3StatusOK) {
- if (!data.headerPrinted) {
- printListServiceHeader(allDetails);
- }
- }
- else {
- printError();
- }
- S3_deinitialize();
- }
- // test bucket ---------------------------------------------------------------
- static void test_bucket(int argc, char **argv, int optindex)
- {
- // test bucket
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex++];
- if (optindex != argc) {
- fprintf(stderr, "\nERROR: Extraneous parameter: %s\n", argv[optindex]);
- usageExit(stderr);
- }
- S3_init();
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback, &responseCompleteCallback
- };
- char locationConstraint[64];
- do {
- S3_test_bucket(protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG, 0,
- 0, bucketName, awsRegionG, sizeof(locationConstraint),
- locationConstraint, 0, timeoutMsG, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- const char *result;
- switch (statusG) {
- case S3StatusOK:
- // bucket exists
- result = locationConstraint[0] ? locationConstraint : "USA";
- break;
- case S3StatusErrorNoSuchBucket:
- result = "Does Not Exist";
- break;
- case S3StatusErrorAccessDenied:
- result = "Access Denied";
- break;
- default:
- result = 0;
- break;
- }
- if (result) {
- printf("%-56s %-20s\n", " Bucket",
- " Status");
- printf("-------------------------------------------------------- "
- "--------------------\n");
- printf("%-56s %-20s\n", bucketName, result);
- }
- else {
- printError();
- }
- S3_deinitialize();
- }
- // create bucket -------------------------------------------------------------
- static void create_bucket(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex++];
- if (!forceG && (S3_validate_bucket_name
- (bucketName, S3UriStyleVirtualHost) != S3StatusOK)) {
- fprintf(stderr, "\nWARNING: Bucket name is not valid for "
- "virtual-host style URI access.\n");
- fprintf(stderr, "Bucket not created. Use -f option to force the "
- "bucket to be created despite\n");
- fprintf(stderr, "this warning.\n\n");
- exit(-1);
- }
- const char *locationConstraint = 0;
- S3CannedAcl cannedAcl = S3CannedAclPrivate;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, LOCATION_PREFIX, LOCATION_PREFIX_LEN)) {
- locationConstraint = &(param[LOCATION_PREFIX_LEN]);
- }
- else if (!strncmp(param, CANNED_ACL_PREFIX, CANNED_ACL_PREFIX_LEN)) {
- char *val = &(param[CANNED_ACL_PREFIX_LEN]);
- if (!strcmp(val, "private")) {
- cannedAcl = S3CannedAclPrivate;
- }
- else if (!strcmp(val, "public-read")) {
- cannedAcl = S3CannedAclPublicRead;
- }
- else if (!strcmp(val, "public-read-write")) {
- cannedAcl = S3CannedAclPublicReadWrite;
- }
- else if (!strcmp(val, "authenticated-read")) {
- cannedAcl = S3CannedAclAuthenticatedRead;
- }
- else {
- fprintf(stderr, "\nERROR: Unknown canned ACL: %s\n", val);
- usageExit(stderr);
- }
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- S3_init();
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback, &responseCompleteCallback
- };
- do {
- S3_create_bucket(protocolG, accessKeyIdG, secretAccessKeyG, 0, 0,
- bucketName, awsRegionG, cannedAcl, locationConstraint,
- 0, 0, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG == S3StatusOK) {
- printf("Bucket successfully created.\n");
- }
- else {
- printError();
- }
- S3_deinitialize();
- }
- // delete bucket -------------------------------------------------------------
- static void delete_bucket(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex++];
- if (optindex != argc) {
- fprintf(stderr, "\nERROR: Extraneous parameter: %s\n", argv[optindex]);
- usageExit(stderr);
- }
- S3_init();
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback, &responseCompleteCallback
- };
- do {
- S3_delete_bucket(protocolG, uriStyleG, accessKeyIdG, secretAccessKeyG,
- 0, 0, bucketName, awsRegionG, 0, timeoutMsG, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- printError();
- }
- S3_deinitialize();
- }
- // list bucket ---------------------------------------------------------------
- typedef struct list_bucket_callback_data
- {
- int isTruncated;
- char nextMarker[1024];
- int keyCount;
- int allDetails;
- } list_bucket_callback_data;
- static void printListBucketHeader(int allDetails)
- {
- printf("%-50s %-20s %-5s",
- " Key",
- " Last Modified", "Size");
- if (allDetails) {
- printf(" %-34s %-64s %-12s",
- " ETag",
- " Owner ID",
- "Display Name");
- }
- printf("\n");
- printf("-------------------------------------------------- "
- "-------------------- -----");
- if (allDetails) {
- printf(" ---------------------------------- "
- "-------------------------------------------------"
- "--------------- ------------");
- }
- printf("\n");
- }
- static S3Status listBucketCallback(int isTruncated, const char *nextMarker,
- int contentsCount,
- const S3ListBucketContent *contents,
- int commonPrefixesCount,
- const char **commonPrefixes,
- void *callbackData)
- {
- list_bucket_callback_data *data =
- (list_bucket_callback_data *) callbackData;
- data->isTruncated = isTruncated;
- // This is tricky. S3 doesn't return the NextMarker if there is no
- // delimiter. Why, I don't know, since it's still useful for paging
- // through results. We want NextMarker to be the last content in the
- // list, so set it to that if necessary.
- if ((!nextMarker || !nextMarker[0]) && contentsCount) {
- nextMarker = contents[contentsCount - 1].key;
- }
- if (nextMarker) {
- snprintf(data->nextMarker, sizeof(data->nextMarker), "%s",
- nextMarker);
- }
- else {
- data->nextMarker[0] = 0;
- }
- if (contentsCount && !data->keyCount) {
- printListBucketHeader(data->allDetails);
- }
- int i;
- for (i = 0; i < contentsCount; i++) {
- const S3ListBucketContent *content = &(contents[i]);
- char timebuf[256];
- if (0) {
- time_t t = (time_t) content->lastModified;
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ",
- gmtime(&t));
- printf("\nKey: %s\n", content->key);
- printf("Last Modified: %s\n", timebuf);
- printf("ETag: %s\n", content->eTag);
- printf("Size: %llu\n", (unsigned long long) content->size);
- if (content->ownerId) {
- printf("Owner ID: %s\n", content->ownerId);
- }
- if (content->ownerDisplayName) {
- printf("Owner Display Name: %s\n", content->ownerDisplayName);
- }
- }
- else {
- time_t t = (time_t) content->lastModified;
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ",
- gmtime(&t));
- char sizebuf[16];
- if (content->size < 100000) {
- sprintf(sizebuf, "%5llu", (unsigned long long) content->size);
- }
- else if (content->size < (1024 * 1024)) {
- sprintf(sizebuf, "%4lluK",
- ((unsigned long long) content->size) / 1024ULL);
- }
- else if (content->size < (10 * 1024 * 1024)) {
- float f = content->size;
- f /= (1024 * 1024);
- sprintf(sizebuf, "%1.2fM", f);
- }
- else if (content->size < (1024 * 1024 * 1024)) {
- sprintf(sizebuf, "%4lluM",
- ((unsigned long long) content->size) /
- (1024ULL * 1024ULL));
- }
- else {
- float f = (content->size / 1024);
- f /= (1024 * 1024);
- sprintf(sizebuf, "%1.2fG", f);
- }
- printf("%-50s %s %s", content->key, timebuf, sizebuf);
- if (data->allDetails) {
- printf(" %-34s %-64s %-12s",
- content->eTag,
- content->ownerId ? content->ownerId : "",
- content->ownerDisplayName ?
- content->ownerDisplayName : "");
- }
- printf("\n");
- }
- }
- data->keyCount += contentsCount;
- for (i = 0; i < commonPrefixesCount; i++) {
- printf("\nCommon Prefix: %s\n", commonPrefixes[i]);
- }
- return S3StatusOK;
- }
- static void list_bucket(const char *bucketName, const char *prefix,
- const char *marker, const char *delimiter,
- int maxkeys, int allDetails)
- {
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ListBucketHandler listBucketHandler =
- {
- { &responsePropertiesCallback, &responseCompleteCallback },
- &listBucketCallback
- };
- list_bucket_callback_data data;
- if (marker) {
- snprintf(data.nextMarker, sizeof(data.nextMarker), "%s", marker);
- } else {
- data.nextMarker[0] = 0;
- }
- data.keyCount = 0;
- data.allDetails = allDetails;
- do {
- data.isTruncated = 0;
- do {
- S3_list_bucket(&bucketContext, prefix, data.nextMarker,
- delimiter, maxkeys, 0, timeoutMsG, &listBucketHandler, &data);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- break;
- }
- } while (data.isTruncated && (!maxkeys || (data.keyCount < maxkeys)));
- if (statusG == S3StatusOK) {
- if (!data.keyCount) {
- printListBucketHeader(allDetails);
- }
- }
- else {
- printError();
- }
- S3_deinitialize();
- }
- static void list(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- list_service(0);
- return;
- }
- const char *bucketName = 0;
- const char *prefix = 0, *marker = 0, *delimiter = 0;
- int maxkeys = 0, allDetails = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, PREFIX_PREFIX, PREFIX_PREFIX_LEN)) {
- prefix = &(param[PREFIX_PREFIX_LEN]);
- }
- else if (!strncmp(param, MARKER_PREFIX, MARKER_PREFIX_LEN)) {
- marker = &(param[MARKER_PREFIX_LEN]);
- }
- else if (!strncmp(param, DELIMITER_PREFIX, DELIMITER_PREFIX_LEN)) {
- delimiter = &(param[DELIMITER_PREFIX_LEN]);
- }
- else if (!strncmp(param, MAXKEYS_PREFIX, MAXKEYS_PREFIX_LEN)) {
- maxkeys = convertInt(&(param[MAXKEYS_PREFIX_LEN]), "maxkeys");
- }
- else if (!strncmp(param, ALL_DETAILS_PREFIX,
- ALL_DETAILS_PREFIX_LEN)) {
- const char *ad = &(param[ALL_DETAILS_PREFIX_LEN]);
- if (!strcmp(ad, "true") || !strcmp(ad, "TRUE") ||
- !strcmp(ad, "yes") || !strcmp(ad, "YES") ||
- !strcmp(ad, "1")) {
- allDetails = 1;
- }
- }
- else if (!bucketName) {
- bucketName = param;
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- if (bucketName) {
- list_bucket(bucketName, prefix, marker, delimiter, maxkeys,
- allDetails);
- }
- else {
- list_service(allDetails);
- }
- }
- typedef struct list_multiparts_callback_data
- {
- int isTruncated;
- char nextKeyMarker[1024];
- char nextUploadIdMarker[1024];
- int uploadCount;
- int allDetails;
- } list_multiparts_callback_data;
- typedef struct UploadManager{
- //used for initial multipart
- char * upload_id;
- //used for upload part object
- char **etags;
- int next_etags_pos;
- //used for commit Upload
- growbuffer *gb;
- int remaining;
- } UploadManager;
- typedef struct list_parts_callback_data
- {
- int isTruncated;
- char nextPartNumberMarker[24];
- char initiatorId[256];
- char initiatorDisplayName[256];
- char ownerId[256];
- char ownerDisplayName[256];
- char storageClass[256];
- int partsCount;
- int handlePartsStart;
- int allDetails;
- int noPrint;
- UploadManager *manager;
- } list_parts_callback_data;
- typedef struct list_upload_callback_data
- {
- char uploadId[1024];
- } abort_upload_callback_data;
- static void printListMultipartHeader(int allDetails)
- {
- (void)allDetails;
- }
- static void printListPartsHeader()
- {
- printf("%-25s %-30s %-30s %-15s",
- "LastModified",
- "PartNumber", "ETag", "SIZE");
- printf("\n");
- printf("--------------------- "
- " ------------- "
- "------------------------------- "
- " -----");
- printf("\n");
- }
- static S3Status listMultipartCallback(int isTruncated, const char *nextKeyMarker,
- const char *nextUploadIdMarker,
- int uploadsCount,
- const S3ListMultipartUpload *uploads,
- int commonPrefixesCount,
- const char **commonPrefixes,
- void *callbackData)
- {
- list_multiparts_callback_data *data =
- (list_multiparts_callback_data *) callbackData;
- data->isTruncated = isTruncated;
- /*
- // This is tricky. S3 doesn't return the NextMarker if there is no
- // delimiter. Why, I don't know, since it's still useful for paging
- // through results. We want NextMarker to be the last content in the
- // list, so set it to that if necessary.
- if ((!nextKeyMarker || !nextKeyMarker[0]) && uploadsCount) {
- nextKeyMarker = uploads[uploadsCount - 1].key;
- }*/
- if (nextKeyMarker) {
- snprintf(data->nextKeyMarker, sizeof(data->nextKeyMarker), "%s",
- nextKeyMarker);
- }
- else {
- data->nextKeyMarker[0] = 0;
- }
- if (nextUploadIdMarker) {
- snprintf(data->nextUploadIdMarker, sizeof(data->nextUploadIdMarker), "%s",
- nextUploadIdMarker);
- }
- else {
- data->nextUploadIdMarker[0] = 0;
- }
- if (uploadsCount && !data->uploadCount) {
- printListMultipartHeader(data->allDetails);
- }
- int i;
- for (i = 0; i < uploadsCount; i++) {
- const S3ListMultipartUpload *upload = &(uploads[i]);
- char timebuf[256];
- if (1) {
- time_t t = (time_t) upload->initiated;
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ",
- gmtime(&t));
- printf("\nKey: %s\n", upload->key);
- printf("Initiated: %s\n", timebuf);
- printf("UploadId: %s\n", upload->uploadId);
- if (upload->initiatorId) {
- printf("Initiator ID: %s\n", upload->initiatorId);
- }
- if (upload->initiatorDisplayName) {
- printf("Initiator Display Name: %s\n", upload->initiatorDisplayName);
- }
- if (upload->ownerId) {
- printf("Owner ID: %s\n", upload->ownerId);
- }
- if (upload->ownerDisplayName) {
- printf("Owner Display Name: %s\n", upload->ownerDisplayName);
- }
- printf("StorageClass: %s\n", upload->storageClass);
- }
- else {
- time_t t = (time_t) upload->initiated;
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ",
- gmtime(&t));
- printf("%-50s %s %-50s", upload->key, timebuf, upload->uploadId);
- if (data->allDetails) {
- printf(" %-34s %-64s %-12s %-64s %-12s",
- upload->storageClass,
- upload->ownerId ? upload->ownerId : "",
- upload->ownerDisplayName ?
- upload->ownerDisplayName : "",
- upload->initiatorId ? upload->initiatorId : "",
- upload->initiatorDisplayName ?
- upload->initiatorDisplayName : "");
- }
- printf("\n");
- }
- }
- data->uploadCount += uploadsCount;
- for (i = 0; i < commonPrefixesCount; i++) {
- printf("\nCommon Prefix: %s\n", commonPrefixes[i]);
- }
- return S3StatusOK;
- }
- static S3Status listPartsCallback(int isTruncated,
- const char *nextPartNumberMarker,
- const char *initiatorId,
- const char *initiatorDisplayName,
- const char *ownerId,
- const char *ownerDisplayName,
- const char *storageClass,
- int partsCount,
- int handlePartsStart,
- const S3ListPart *parts,
- void *callbackData)
- {
- list_parts_callback_data *data =
- (list_parts_callback_data *) callbackData;
- data->isTruncated = isTruncated;
- data->handlePartsStart = handlePartsStart;
- UploadManager *manager = data->manager;
- /*
- // This is tricky. S3 doesn't return the NextMarker if there is no
- // delimiter. Why, I don't know, since it's still useful for paging
- // through results. We want NextMarker to be the last content in the
- // list, so set it to that if necessary.
- if ((!nextKeyMarker || !nextKeyMarker[0]) && uploadsCount) {
- nextKeyMarker = uploads[uploadsCount - 1].key;
- }*/
- if (nextPartNumberMarker) {
- snprintf(data->nextPartNumberMarker,
- sizeof(data->nextPartNumberMarker), "%s",
- nextPartNumberMarker);
- }
- else {
- data->nextPartNumberMarker[0] = 0;
- }
- if (initiatorId) {
- snprintf(data->initiatorId, sizeof(data->initiatorId), "%s",
- initiatorId);
- }
- else {
- data->initiatorId[0] = 0;
- }
- if (initiatorDisplayName) {
- snprintf(data->initiatorDisplayName,
- sizeof(data->initiatorDisplayName), "%s",
- initiatorDisplayName);
- }
- else {
- data->initiatorDisplayName[0] = 0;
- }
- if (ownerId) {
- snprintf(data->ownerId, sizeof(data->ownerId), "%s",
- ownerId);
- }
- else {
- data->ownerId[0] = 0;
- }
- if (ownerDisplayName) {
- snprintf(data->ownerDisplayName, sizeof(data->ownerDisplayName), "%s",
- ownerDisplayName);
- }
- else {
- data->ownerDisplayName[0] = 0;
- }
- if (storageClass) {
- snprintf(data->storageClass, sizeof(data->storageClass), "%s",
- storageClass);
- }
- else {
- data->storageClass[0] = 0;
- }
- if (partsCount && !data->partsCount && !data->noPrint) {
- printListPartsHeader();
- }
- int i;
- for (i = 0; i < partsCount; i++) {
- const S3ListPart *part = &(parts[i]);
- char timebuf[256];
- if (data->noPrint) {
- manager->etags[handlePartsStart+i] = strdup(part->eTag);
- manager->next_etags_pos++;
- manager->remaining = manager->remaining - part->size;
- } else {
- time_t t = (time_t) part->lastModified;
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ",
- gmtime(&t));
- printf("%-30s", timebuf);
- printf("%-15llu", (unsigned long long) part->partNumber);
- printf("%-45s", part->eTag);
- printf("%-15llu\n", (unsigned long long) part->size);
- }
- }
- data->partsCount += partsCount;
- return S3StatusOK;
- }
- static void list_multipart_uploads(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Usage: listmultiparts <bucket name>\n");
- return;
- }
- const char *bucketName = 0;
- const char *prefix = 0, *keymarker = 0, *delimiter = 0;
- const char *encodingtype = 0, *uploadidmarker = 0;
- int maxuploads = 0, allDetails = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, PREFIX_PREFIX, PREFIX_PREFIX_LEN)) {
- prefix = &(param[PREFIX_PREFIX_LEN]);
- }
- else if (!strncmp(param, KEY_MARKER_PREFIX, KEY_MARKER_PREFIX_LEN)) {
- keymarker = &(param[KEY_MARKER_PREFIX_LEN]);
- }
- else if (!strncmp(param, DELIMITER_PREFIX, DELIMITER_PREFIX_LEN)) {
- delimiter = &(param[DELIMITER_PREFIX_LEN]);
- }
- else if (!strncmp(param, ENCODING_TYPE_PREFIX,
- ENCODING_TYPE_PREFIX_LEN)) {
- encodingtype = &(param[ENCODING_TYPE_PREFIX_LEN]);
- }
- else if (!strncmp(param, UPLOAD_ID_MARKER_PREFIX,
- UPLOAD_ID_MARKER_PREFIX_LEN)) {
- uploadidmarker = &(param[UPLOAD_ID_MARKER_PREFIX_LEN]);
- }
- else if (!strncmp(param, MAX_UPLOADS_PREFIX, MAX_UPLOADS_PREFIX_LEN)) {
- maxuploads = convertInt(&(param[MAX_UPLOADS_PREFIX_LEN]),
- "maxuploads");
- }
- else if (!strncmp(param, ALL_DETAILS_PREFIX, ALL_DETAILS_PREFIX_LEN)) {
- const char *ad = &(param[ALL_DETAILS_PREFIX_LEN]);
- if (!strcmp(ad, "true") || !strcmp(ad, "TRUE") ||
- !strcmp(ad, "yes") || !strcmp(ad, "YES") ||
- !strcmp(ad, "1")) {
- allDetails = 1;
- }
- }
- else if (!bucketName) {
- bucketName = param;
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- if (bucketName) {
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ListMultipartUploadsHandler listMultipartUploadsHandler =
- {
- { &responsePropertiesCallback, &responseCompleteCallback },
- &listMultipartCallback
- };
- list_multiparts_callback_data data;
- memset(&data, 0, sizeof(list_multiparts_callback_data));
- if (keymarker != 0) {
- snprintf(data.nextKeyMarker, sizeof(data.nextKeyMarker), "%s",
- keymarker);
- }
- if (uploadidmarker != 0) {
- snprintf(data.nextUploadIdMarker, sizeof(data.nextUploadIdMarker),
- "%s", uploadidmarker);
- }
- data.uploadCount = 0;
- data.allDetails = allDetails;
- do {
- data.isTruncated = 0;
- do {
- S3_list_multipart_uploads(&bucketContext, prefix,
- data.nextKeyMarker,
- data.nextUploadIdMarker, encodingtype,
- delimiter, maxuploads, 0,
- timeoutMsG,
- &listMultipartUploadsHandler, &data);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- break;
- }
- } while (data.isTruncated &&
- (!maxuploads || (data.uploadCount < maxuploads)));
- if (statusG == S3StatusOK) {
- if (!data.uploadCount) {
- printListMultipartHeader(data.allDetails);
- }
- }
- else {
- printError();
- }
- S3_deinitialize();
- }
- }
- static void list_parts(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Usage: listparts <bucket name> <filename> "
- "<upload-id>\n");
- return;
- }
- // Split bucket/key
- char *slash = argv[optindex];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (!*slash || !*(slash + 1)) {
- fprintf(stderr, "\nERROR: Invalid bucket/key name: %s\n",
- argv[optindex]);
- usageExit(stderr);
- }
- *slash++ = 0;
- const char *bucketName = argv[optindex++];
- const char *key = slash;
- const char *uploadid = 0, *partnumbermarker = 0;
- const char *encodingtype = 0;
- int allDetails = 0, maxparts = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, UPLOAD_ID_PREFIX, UPLOAD_ID_PREFIX_LEN)) {
- uploadid = &(param[UPLOAD_ID_PREFIX_LEN]);
- }
- else if (!strncmp(param, PART_NUMBER_MARKER_PREFIX,
- PART_NUMBER_MARKER_PREFIX_LEN)) {
- partnumbermarker = &(param[PART_NUMBER_MARKER_PREFIX_LEN]);
- }
- else if (!strncmp(param, ENCODING_TYPE_PREFIX,
- ENCODING_TYPE_PREFIX_LEN)) {
- encodingtype = &(param[ENCODING_TYPE_PREFIX_LEN]);
- }
- else if (!strncmp(param, MAX_PARTS_PREFIX, MAX_PARTS_PREFIX_LEN)) {
- maxparts = convertInt(&(param[MAX_PARTS_PREFIX_LEN]), "max-parts");
- }
- else if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- key = &(param[FILENAME_PREFIX_LEN]);
- }
- else if (!strncmp(param, ALL_DETAILS_PREFIX,
- ALL_DETAILS_PREFIX_LEN)) {
- const char *ad = &(param[ALL_DETAILS_PREFIX_LEN]);
- if (!strcmp(ad, "true") || !strcmp(ad, "TRUE") ||
- !strcmp(ad, "yes") || !strcmp(ad, "YES") ||
- !strcmp(ad, "1")) {
- allDetails = 1;
- }
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- if (bucketName) {
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ListPartsHandler listPartsHandler =
- {
- { &responsePropertiesCallback, &responseCompleteCallback },
- &listPartsCallback
- };
- list_parts_callback_data data;
- memset(&data, 0, sizeof(list_parts_callback_data));
- if (partnumbermarker != 0) {
- snprintf(data.nextPartNumberMarker,
- sizeof(data.nextPartNumberMarker), "%s", partnumbermarker);
- }
- data.partsCount = 0;
- data.allDetails = allDetails;
- data.noPrint = 0;
- do {
- data.isTruncated = 0;
- do {
- S3_list_parts(&bucketContext, key, data.nextPartNumberMarker,
- uploadid, encodingtype,
- maxparts,
- 0, timeoutMsG,
- &listPartsHandler, &data);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- break;
- }
- } while (data.isTruncated &&
- (!maxparts || (data.partsCount < maxparts)));
- if (statusG == S3StatusOK) {
- if (!data.partsCount) {
- printListMultipartHeader(data.allDetails);
- }
- }
- else {
- printError();
- }
- S3_deinitialize();
- }
- }
- static void abort_multipart_upload(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Usage: abortmultipartupload <bucket name> "
- "<upload-id>\n");
- return;
- }
- // Split bucket/key
- char *slash = argv[optindex];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (!*slash || !*(slash + 1)) {
- fprintf(stderr, "\nERROR: Invalid bucket/key name: %s\n",
- argv[optindex]);
- usageExit(stderr);
- }
- *slash++ = 0;
- const char *bucketName = argv[optindex++];
- const char *key = slash;
- const char *uploadid = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, UPLOAD_ID_PREFIX, UPLOAD_ID_PREFIX_LEN)) {
- uploadid = &(param[UPLOAD_ID_PREFIX_LEN]);
- }
- else if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- key = &(param[FILENAME_PREFIX_LEN]);
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- if (bucketName) {
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3AbortMultipartUploadHandler abortMultipartUploadHandler =
- {
- { &responsePropertiesCallback, &responseCompleteCallback },
- };
- /*
- list_multiparts_callback_data data;
- memset(&data, 0, sizeof(list_multiparts_callback_data));
- if (keymarker != 0) {
- snprintf(data.nextKeyMarker, sizeof(data.nextKeyMarker), "%s",
- keymarker);
- }
- if (uploadidmarker != 0) {
- snprintf(data.nextUploadIdMarker, sizeof(data.nextUploadIdMarker),
- "%s", uploadidmarker);
- }
- data.uploadCount = 0;
- data.allDetails = allDetails;
- */
- do {
- S3_abort_multipart_upload(&bucketContext, key, uploadid,
- timeoutMsG, &abortMultipartUploadHandler);
- } while (S3_status_is_retryable(statusG) && should_retry());
- S3_deinitialize();
- }
- }
- // delete object -------------------------------------------------------------
- static void delete_object(int argc, char **argv, int optindex)
- {
- (void) argc;
- // Split bucket/key
- char *slash = argv[optindex];
- // We know there is a slash in there, put_object is only called if so
- while (*slash && (*slash != '/')) {
- slash++;
- }
- *slash++ = 0;
- const char *bucketName = argv[optindex++];
- const char *key = slash;
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ResponseHandler responseHandler =
- {
- 0,
- &responseCompleteCallback
- };
- do {
- S3_delete_object(&bucketContext, key, 0, timeoutMsG, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if ((statusG != S3StatusOK) &&
- (statusG != S3StatusErrorPreconditionFailed)) {
- printError();
- }
- S3_deinitialize();
- }
- // put object ----------------------------------------------------------------
- typedef struct put_object_callback_data
- {
- FILE *infile;
- growbuffer *gb;
- uint64_t contentLength, originalContentLength;
- uint64_t totalContentLength, totalOriginalContentLength;
- int noStatus;
- } put_object_callback_data;
- static int putObjectDataCallback(int bufferSize, char *buffer,
- void *callbackData)
- {
- put_object_callback_data *data =
- (put_object_callback_data *) callbackData;
- int ret = 0;
- if (data->contentLength) {
- int toRead = ((data->contentLength > (unsigned) bufferSize) ?
- (unsigned) bufferSize : data->contentLength);
- if (data->gb) {
- growbuffer_read(&(data->gb), toRead, &ret, buffer);
- }
- else if (data->infile) {
- ret = fread(buffer, 1, toRead, data->infile);
- }
- }
- data->contentLength -= ret;
- data->totalContentLength -= ret;
- if (data->contentLength && !data->noStatus) {
- // Avoid a weird bug in MingW, which won't print the second integer
- // value properly when it's in the same call, so print separately
- printf("%llu bytes remaining ",
- (unsigned long long) data->totalContentLength);
- printf("(%d%% complete) ...\n",
- (int) (((data->totalOriginalContentLength -
- data->totalContentLength) * 100) /
- data->totalOriginalContentLength));
- }
- return ret;
- }
- #define MULTIPART_CHUNK_SIZE (15 << 20) // multipart is 15M
- typedef struct MultipartPartData {
- put_object_callback_data put_object_data;
- int seq;
- UploadManager *manager;
- } MultipartPartData;
- S3Status initial_multipart_callback(const char * upload_id,
- void * callbackData)
- {
- UploadManager *manager = (UploadManager *) callbackData;
- manager->upload_id = strdup(upload_id);
- return S3StatusOK;
- }
- S3Status MultipartResponseProperiesCallback
- (const S3ResponseProperties *properties, void *callbackData)
- {
- responsePropertiesCallback(properties, callbackData);
- MultipartPartData *data = (MultipartPartData *) callbackData;
- int seq = data->seq;
- const char *etag = properties->eTag;
- data->manager->etags[seq - 1] = strdup(etag);
- data->manager->next_etags_pos = seq;
- return S3StatusOK;
- }
- static int multipartPutXmlCallback(int bufferSize, char *buffer,
- void *callbackData)
- {
- UploadManager *manager = (UploadManager*)callbackData;
- int ret = 0;
- if (manager->remaining) {
- int toRead = ((manager->remaining > bufferSize) ?
- bufferSize : manager->remaining);
- growbuffer_read(&(manager->gb), toRead, &ret, buffer);
- }
- manager->remaining -= ret;
- return ret;
- }
- static int try_get_parts_info(const char *bucketName, const char *key,
- UploadManager *manager)
- {
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ListPartsHandler listPartsHandler =
- {
- { &responsePropertiesCallback, &responseCompleteCallback },
- &listPartsCallback
- };
- list_parts_callback_data data;
- memset(&data, 0, sizeof(list_parts_callback_data));
- data.partsCount = 0;
- data.allDetails = 0;
- data.manager = manager;
- data.noPrint = 1;
- do {
- data.isTruncated = 0;
- do {
- S3_list_parts(&bucketContext, key, data.nextPartNumberMarker,
- manager->upload_id, 0, 0, 0, timeoutMsG, &listPartsHandler,
- &data);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- break;
- }
- } while (data.isTruncated);
- if (statusG == S3StatusOK) {
- if (!data.partsCount) {
- printListMultipartHeader(data.allDetails);
- }
- }
- else {
- printError();
- return -1;
- }
- return 0;
- }
- static void put_object(int argc, char **argv, int optindex,
- const char *srcBucketName, const char *srcKey, unsigned long long srcSize)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket/key\n");
- usageExit(stderr);
- }
- // Split bucket/key
- char *slash = argv[optindex];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (!*slash || !*(slash + 1)) {
- fprintf(stderr, "\nERROR: Invalid bucket/key name: %s\n",
- argv[optindex]);
- usageExit(stderr);
- }
- *slash++ = 0;
- const char *bucketName = argv[optindex++];
- const char *key = slash;
- const char *uploadId = 0;
- const char *filename = 0;
- uint64_t contentLength = 0;
- const char *cacheControl = 0, *contentType = 0, *md5 = 0;
- const char *contentDispositionFilename = 0, *contentEncoding = 0;
- int64_t expires = -1;
- S3CannedAcl cannedAcl = S3CannedAclPrivate;
- int metaPropertiesCount = 0;
- S3NameValue metaProperties[S3_MAX_METADATA_COUNT];
- char useServerSideEncryption = 0;
- int noStatus = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- filename = &(param[FILENAME_PREFIX_LEN]);
- }
- else if (!strncmp(param, CONTENT_LENGTH_PREFIX,
- CONTENT_LENGTH_PREFIX_LEN)) {
- contentLength = convertInt(&(param[CONTENT_LENGTH_PREFIX_LEN]),
- "contentLength");
- if (contentLength > (5LL * 1024 * 1024 * 1024)) {
- fprintf(stderr, "\nERROR: contentLength must be no greater "
- "than 5 GB\n");
- usageExit(stderr);
- }
- }
- else if (!strncmp(param, CACHE_CONTROL_PREFIX,
- CACHE_CONTROL_PREFIX_LEN)) {
- cacheControl = &(param[CACHE_CONTROL_PREFIX_LEN]);
- }
- else if (!strncmp(param, CONTENT_TYPE_PREFIX,
- CONTENT_TYPE_PREFIX_LEN)) {
- contentType = &(param[CONTENT_TYPE_PREFIX_LEN]);
- }
- else if (!strncmp(param, MD5_PREFIX, MD5_PREFIX_LEN)) {
- md5 = &(param[MD5_PREFIX_LEN]);
- }
- else if (!strncmp(param, CONTENT_DISPOSITION_FILENAME_PREFIX,
- CONTENT_DISPOSITION_FILENAME_PREFIX_LEN)) {
- contentDispositionFilename =
- &(param[CONTENT_DISPOSITION_FILENAME_PREFIX_LEN]);
- }
- else if (!strncmp(param, CONTENT_ENCODING_PREFIX,
- CONTENT_ENCODING_PREFIX_LEN)) {
- contentEncoding = &(param[CONTENT_ENCODING_PREFIX_LEN]);
- }
- else if (!strncmp(param, UPLOAD_ID_PREFIX,
- UPLOAD_ID_PREFIX_LEN)) {
- uploadId = &(param[UPLOAD_ID_PREFIX_LEN]);
- }
- else if (!strncmp(param, EXPIRES_PREFIX, EXPIRES_PREFIX_LEN)) {
- expires = parseIso8601Time(&(param[EXPIRES_PREFIX_LEN]));
- if (expires < 0) {
- fprintf(stderr, "\nERROR: Invalid expires time "
- "value; ISO 8601 time format required\n");
- usageExit(stderr);
- }
- }
- else if (!strncmp(param, X_AMZ_META_PREFIX, X_AMZ_META_PREFIX_LEN)) {
- if (metaPropertiesCount == S3_MAX_METADATA_COUNT) {
- fprintf(stderr, "\nERROR: Too many x-amz-meta- properties, "
- "limit %lu: %s\n",
- (unsigned long) S3_MAX_METADATA_COUNT, param);
- usageExit(stderr);
- }
- char *name = &(param[X_AMZ_META_PREFIX_LEN]);
- char *value = name;
- while (*value && (*value != '=')) {
- value++;
- }
- if (!*value || !*(value + 1)) {
- fprintf(stderr, "\nERROR: Invalid parameter: %s\n", param);
- usageExit(stderr);
- }
- *value++ = 0;
- metaProperties[metaPropertiesCount].name = name;
- metaProperties[metaPropertiesCount++].value = value;
- }
- else if (!strncmp(param, USE_SERVER_SIDE_ENCRYPTION_PREFIX,
- USE_SERVER_SIDE_ENCRYPTION_PREFIX_LEN)) {
- const char *val = &(param[USE_SERVER_SIDE_ENCRYPTION_PREFIX_LEN]);
- if (!strcmp(val, "true") || !strcmp(val, "TRUE") ||
- !strcmp(val, "yes") || !strcmp(val, "YES") ||
- !strcmp(val, "1")) {
- useServerSideEncryption = 1;
- }
- else {
- useServerSideEncryption = 0;
- }
- }
- else if (!strncmp(param, CANNED_ACL_PREFIX, CANNED_ACL_PREFIX_LEN)) {
- char *val = &(param[CANNED_ACL_PREFIX_LEN]);
- if (!strcmp(val, "private")) {
- cannedAcl = S3CannedAclPrivate;
- }
- else if (!strcmp(val, "public-read")) {
- cannedAcl = S3CannedAclPublicRead;
- }
- else if (!strcmp(val, "public-read-write")) {
- cannedAcl = S3CannedAclPublicReadWrite;
- }
- else if (!strcmp(val, "authenticated-read")) {
- cannedAcl = S3CannedAclAuthenticatedRead;
- }
- else {
- fprintf(stderr, "\nERROR: Unknown canned ACL: %s\n", val);
- usageExit(stderr);
- }
- }
- else if (!strncmp(param, NO_STATUS_PREFIX, NO_STATUS_PREFIX_LEN)) {
- const char *ns = &(param[NO_STATUS_PREFIX_LEN]);
- if (!strcmp(ns, "true") || !strcmp(ns, "TRUE") ||
- !strcmp(ns, "yes") || !strcmp(ns, "YES") ||
- !strcmp(ns, "1")) {
- noStatus = 1;
- }
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- put_object_callback_data data;
- data.infile = 0;
- data.gb = 0;
- data.noStatus = noStatus;
- if (srcSize) {
- // This is really a COPY multipart, not a put, so take from source object
- contentLength = srcSize;
- data.infile = NULL;
- }
- else if (filename) {
- if (!contentLength) {
- struct stat statbuf;
- // Stat the file to get its length
- if (stat(filename, &statbuf) == -1) {
- fprintf(stderr, "\nERROR: Failed to stat file %s: ",
- filename);
- perror(0);
- exit(-1);
- }
- contentLength = statbuf.st_size;
- }
- // Open the file
- if (!(data.infile = fopen(filename, "r" FOPEN_EXTRA_FLAGS))) {
- fprintf(stderr, "\nERROR: Failed to open input file %s: ",
- filename);
- perror(0);
- exit(-1);
- }
- }
- else {
- // Read from stdin. If contentLength is not provided, we have
- // to read it all in to get contentLength.
- if (!contentLength) {
- // Read all if stdin to get the data
- char buffer[64 * 1024];
- while (1) {
- int amtRead = fread(buffer, 1, sizeof(buffer), stdin);
- if (amtRead == 0) {
- break;
- }
- if (!growbuffer_append(&(data.gb), buffer, amtRead)) {
- fprintf(stderr, "\nERROR: Out of memory while reading "
- "stdin\n");
- exit(-1);
- }
- contentLength += amtRead;
- if (amtRead < (int) sizeof(buffer)) {
- break;
- }
- }
- }
- else {
- data.infile = stdin;
- }
- }
- data.totalContentLength =
- data.totalOriginalContentLength =
- data.contentLength =
- data.originalContentLength =
- contentLength;
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3PutProperties putProperties =
- {
- contentType,
- md5,
- cacheControl,
- contentDispositionFilename,
- contentEncoding,
- expires,
- cannedAcl,
- metaPropertiesCount,
- metaProperties,
- useServerSideEncryption
- };
- if (contentLength <= MULTIPART_CHUNK_SIZE) {
- S3PutObjectHandler putObjectHandler =
- {
- { &responsePropertiesCallback, &responseCompleteCallback },
- &putObjectDataCallback
- };
- do {
- S3_put_object(&bucketContext, key, contentLength, &putProperties, 0,
- 0, &putObjectHandler, &data);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (data.infile) {
- fclose(data.infile);
- }
- else if (data.gb) {
- growbuffer_destroy(data.gb);
- }
- if (statusG != S3StatusOK) {
- printError();
- }
- else if (data.contentLength) {
- fprintf(stderr, "\nERROR: Failed to read remaining %llu bytes from "
- "input\n", (unsigned long long) data.contentLength);
- }
- }
- else {
- uint64_t totalContentLength = contentLength;
- uint64_t todoContentLength = contentLength;
- UploadManager manager;
- manager.upload_id = 0;
- manager.gb = 0;
- //div round up
- int seq;
- int totalSeq = ((contentLength + MULTIPART_CHUNK_SIZE- 1) /
- MULTIPART_CHUNK_SIZE);
- MultipartPartData partData;
- int partContentLength = 0;
- S3MultipartInitialHandler handler = {
- {
- &responsePropertiesCallback,
- &responseCompleteCallback
- },
- &initial_multipart_callback
- };
- S3PutObjectHandler putObjectHandler = {
- {&MultipartResponseProperiesCallback, &responseCompleteCallback },
- &putObjectDataCallback
- };
- S3MultipartCommitHandler commit_handler = {
- {
- &responsePropertiesCallback,&responseCompleteCallback
- },
- &multipartPutXmlCallback,
- 0
- };
- manager.etags = (char **) malloc(sizeof(char *) * totalSeq);
- manager.next_etags_pos = 0;
- if (uploadId) {
- manager.upload_id = strdup(uploadId);
- manager.remaining = contentLength;
- if (!try_get_parts_info(bucketName, key, &manager)) {
- fseek(data.infile, -(manager.remaining), 2);
- contentLength = manager.remaining;
- goto upload;
- } else {
- goto clean;
- }
- }
- do {
- S3_initiate_multipart(&bucketContext, key,0, &handler,0, timeoutMsG, &manager);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (manager.upload_id == 0 || statusG != S3StatusOK) {
- printError();
- goto clean;
- }
- upload:
- todoContentLength -= MULTIPART_CHUNK_SIZE * manager.next_etags_pos;
- for (seq = manager.next_etags_pos + 1; seq <= totalSeq; seq++) {
- memset(&partData, 0, sizeof(MultipartPartData));
- partData.manager = &manager;
- partData.seq = seq;
- partData.put_object_data = data;
- partContentLength = ((contentLength > MULTIPART_CHUNK_SIZE) ?
- MULTIPART_CHUNK_SIZE : contentLength);
- printf("%s Part Seq %d, length=%d\n", srcSize ? "Copying" : "Sending", seq, partContentLength);
- partData.put_object_data.contentLength = partContentLength;
- partData.put_object_data.originalContentLength = partContentLength;
- partData.put_object_data.totalContentLength = todoContentLength;
- partData.put_object_data.totalOriginalContentLength = totalContentLength;
- putProperties.md5 = 0;
- do {
- if (srcSize) {
- S3BucketContext srcBucketContext =
- {
- 0,
- srcBucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ResponseHandler copyResponseHandler = { &responsePropertiesCallback, &responseCompleteCallback };
- int64_t lastModified;
- unsigned long long startOffset = (unsigned long long)MULTIPART_CHUNK_SIZE * (unsigned long long)(seq-1);
- unsigned long long count = partContentLength - 1; // Inclusive for copies
- // The default copy callback tries to set this for us, need to allocate here
- manager.etags[seq-1] = malloc(512); // TBD - magic #! Isa there a max etag defined?
- S3_copy_object_range(&srcBucketContext, srcKey,
- bucketName, key,
- seq, manager.upload_id,
- startOffset, count,
- &putProperties,
- &lastModified, 512 /*TBD - magic # */,
- manager.etags[seq-1], 0,
- timeoutMsG,
- ©ResponseHandler, 0);
- } else {
- S3_upload_part(&bucketContext, key, &putProperties,
- &putObjectHandler, seq, manager.upload_id,
- partContentLength,
- 0, timeoutMsG,
- &partData);
- }
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- printError();
- goto clean;
- }
- contentLength -= MULTIPART_CHUNK_SIZE;
- todoContentLength -= MULTIPART_CHUNK_SIZE;
- }
- int i;
- int size = 0;
- size += growbuffer_append(&(manager.gb), "<CompleteMultipartUpload>",
- strlen("<CompleteMultipartUpload>"));
- char buf[256];
- int n;
- for (i = 0; i < totalSeq; i++) {
- n = snprintf(buf, sizeof(buf), "<Part><PartNumber>%d</PartNumber>"
- "<ETag>%s</ETag></Part>", i + 1, manager.etags[i]);
- size += growbuffer_append(&(manager.gb), buf, n);
- }
- size += growbuffer_append(&(manager.gb), "</CompleteMultipartUpload>",
- strlen("</CompleteMultipartUpload>"));
- manager.remaining = size;
- do {
- S3_complete_multipart_upload(&bucketContext, key, &commit_handler,
- manager.upload_id, manager.remaining,
- 0, timeoutMsG, &manager);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- printError();
- goto clean;
- }
- clean:
- if(manager.upload_id) {
- free(manager.upload_id);
- }
- for (i = 0; i < manager.next_etags_pos; i++) {
- free(manager.etags[i]);
- }
- growbuffer_destroy(manager.gb);
- free(manager.etags);
- }
- S3_deinitialize();
- }
- // copy object ---------------------------------------------------------------
- static S3Status copyListKeyCallback(int isTruncated, const char *nextMarker,
- int contentsCount,
- const S3ListBucketContent *contents,
- int commonPrefixesCount,
- const char **commonPrefixes,
- void *callbackData)
- {
- unsigned long long *size = (unsigned long long *)callbackData;
- // These are unused, avoid warnings in a hopefully portable way
- (void)(nextMarker);
- (void)(commonPrefixesCount);
- (void)(commonPrefixes);
- (void)(isTruncated);
- if (contentsCount != 1) {
- // We either have no matched or multiples...can't perform the operation
- return S3StatusErrorUnexpectedContent;
- }
- *size = (unsigned long long) contents->size;
- return S3StatusOK;
- }
- static void copy_object(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: source bucket/key\n");
- usageExit(stderr);
- }
- // Split bucket/key
- char *slash = argv[optindex];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (!*slash || !*(slash + 1)) {
- fprintf(stderr, "\nERROR: Invalid source bucket/key name: %s\n",
- argv[optindex]);
- usageExit(stderr);
- }
- *slash++ = 0;
- const char *sourceBucketName = argv[optindex++];
- const char *sourceKey = slash;
- unsigned long long sourceSize = 0;
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: "
- "destination bucket/key\n");
- usageExit(stderr);
- }
- S3_init();
- S3BucketContext listBucketContext =
- {
- 0,
- sourceBucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ListBucketHandler listBucketHandler =
- {
- { &responsePropertiesCallback, &responseCompleteCallback },
- ©ListKeyCallback
- };
- // Find size of existing key to determine if MP required
- do {
- S3_list_bucket(&listBucketContext, sourceKey, NULL,
- ".", 1, 0,
- timeoutMsG, &listBucketHandler, &sourceSize);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- fprintf(stderr, "\nERROR: Unable to get source object size (%s)\n",
- S3_get_status_name(statusG));
- fprintf(stderr, "%s\n", errorDetailsG);
- exit(1);
- }
- if (sourceSize > MULTIPART_CHUNK_SIZE) {
- printf("\nUsing multipart copy because object size %llu is above %d.\n", sourceSize, MULTIPART_CHUNK_SIZE);
- put_object(argc, argv, optindex, sourceBucketName, sourceKey, sourceSize);
- return;
- }
- // Split bucket/key
- slash = argv[optindex];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (!*slash || !*(slash + 1)) {
- fprintf(stderr, "\nERROR: Invalid destination bucket/key name: %s\n",
- argv[optindex]);
- usageExit(stderr);
- }
- *slash++ = 0;
- const char *destinationBucketName = argv[optindex++];
- const char *destinationKey = slash;
- const char *cacheControl = 0, *contentType = 0;
- const char *contentDispositionFilename = 0, *contentEncoding = 0;
- int64_t expires = -1;
- S3CannedAcl cannedAcl = S3CannedAclPrivate;
- int metaPropertiesCount = 0;
- S3NameValue metaProperties[S3_MAX_METADATA_COUNT];
- char useServerSideEncryption = 0;
- int anyPropertiesSet = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, CACHE_CONTROL_PREFIX,
- CACHE_CONTROL_PREFIX_LEN)) {
- cacheControl = &(param[CACHE_CONTROL_PREFIX_LEN]);
- anyPropertiesSet = 1;
- }
- else if (!strncmp(param, CONTENT_TYPE_PREFIX,
- CONTENT_TYPE_PREFIX_LEN)) {
- contentType = &(param[CONTENT_TYPE_PREFIX_LEN]);
- anyPropertiesSet = 1;
- }
- else if (!strncmp(param, CONTENT_DISPOSITION_FILENAME_PREFIX,
- CONTENT_DISPOSITION_FILENAME_PREFIX_LEN)) {
- contentDispositionFilename =
- &(param[CONTENT_DISPOSITION_FILENAME_PREFIX_LEN]);
- anyPropertiesSet = 1;
- }
- else if (!strncmp(param, CONTENT_ENCODING_PREFIX,
- CONTENT_ENCODING_PREFIX_LEN)) {
- contentEncoding = &(param[CONTENT_ENCODING_PREFIX_LEN]);
- anyPropertiesSet = 1;
- }
- else if (!strncmp(param, EXPIRES_PREFIX, EXPIRES_PREFIX_LEN)) {
- expires = parseIso8601Time(&(param[EXPIRES_PREFIX_LEN]));
- if (expires < 0) {
- fprintf(stderr, "\nERROR: Invalid expires time "
- "value; ISO 8601 time format required\n");
- usageExit(stderr);
- }
- anyPropertiesSet = 1;
- }
- else if (!strncmp(param, X_AMZ_META_PREFIX, X_AMZ_META_PREFIX_LEN)) {
- if (metaPropertiesCount == S3_MAX_METADATA_COUNT) {
- fprintf(stderr, "\nERROR: Too many x-amz-meta- properties, "
- "limit %lu: %s\n",
- (unsigned long) S3_MAX_METADATA_COUNT, param);
- usageExit(stderr);
- }
- char *name = &(param[X_AMZ_META_PREFIX_LEN]);
- char *value = name;
- while (*value && (*value != '=')) {
- value++;
- }
- if (!*value || !*(value + 1)) {
- fprintf(stderr, "\nERROR: Invalid parameter: %s\n", param);
- usageExit(stderr);
- }
- *value++ = 0;
- metaProperties[metaPropertiesCount].name = name;
- metaProperties[metaPropertiesCount++].value = value;
- anyPropertiesSet = 1;
- }
- else if (!strncmp(param, USE_SERVER_SIDE_ENCRYPTION_PREFIX,
- USE_SERVER_SIDE_ENCRYPTION_PREFIX_LEN)) {
- if (!strcmp(param, "true") || !strcmp(param, "TRUE") ||
- !strcmp(param, "yes") || !strcmp(param, "YES") ||
- !strcmp(param, "1")) {
- useServerSideEncryption = 1;
- anyPropertiesSet = 1;
- }
- else {
- useServerSideEncryption = 0;
- }
- }
- else if (!strncmp(param, CANNED_ACL_PREFIX, CANNED_ACL_PREFIX_LEN)) {
- char *val = &(param[CANNED_ACL_PREFIX_LEN]);
- if (!strcmp(val, "private")) {
- cannedAcl = S3CannedAclPrivate;
- }
- else if (!strcmp(val, "public-read")) {
- cannedAcl = S3CannedAclPublicRead;
- }
- else if (!strcmp(val, "public-read-write")) {
- cannedAcl = S3CannedAclPublicReadWrite;
- }
- else if (!strcmp(val, "authenticated-read")) {
- cannedAcl = S3CannedAclAuthenticatedRead;
- }
- else {
- fprintf(stderr, "\nERROR: Unknown canned ACL: %s\n", val);
- usageExit(stderr);
- }
- anyPropertiesSet = 1;
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- S3BucketContext bucketContext =
- {
- 0,
- sourceBucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3PutProperties putProperties =
- {
- contentType,
- 0,
- cacheControl,
- contentDispositionFilename,
- contentEncoding,
- expires,
- cannedAcl,
- metaPropertiesCount,
- metaProperties,
- useServerSideEncryption
- };
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback,
- &responseCompleteCallback
- };
- int64_t lastModified;
- char eTag[256];
- do {
- S3_copy_object(&bucketContext, sourceKey, destinationBucketName,
- destinationKey, anyPropertiesSet ? &putProperties : 0,
- &lastModified, sizeof(eTag), eTag, 0,
- timeoutMsG,
- &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG == S3StatusOK) {
- if (lastModified >= 0) {
- char timebuf[256];
- time_t t = (time_t) lastModified;
- strftime(timebuf, sizeof(timebuf), "%Y-%m-%dT%H:%M:%SZ",
- gmtime(&t));
- printf("Last-Modified: %s\n", timebuf);
- }
- if (eTag[0]) {
- printf("ETag: %s\n", eTag);
- }
- }
- else {
- printError();
- }
- S3_deinitialize();
- }
- // get object ----------------------------------------------------------------
- static S3Status getObjectDataCallback(int bufferSize, const char *buffer,
- void *callbackData)
- {
- FILE *outfile = (FILE *) callbackData;
- size_t wrote = fwrite(buffer, 1, bufferSize, outfile);
- return ((wrote < (size_t) bufferSize) ?
- S3StatusAbortedByCallback : S3StatusOK);
- }
- static void get_object(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket/key\n");
- usageExit(stderr);
- }
- // Split bucket/key
- char *slash = argv[optindex];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (!*slash || !*(slash + 1)) {
- fprintf(stderr, "\nERROR: Invalid bucket/key name: %s\n",
- argv[optindex]);
- usageExit(stderr);
- }
- *slash++ = 0;
- const char *bucketName = argv[optindex++];
- const char *key = slash;
- const char *filename = 0;
- int64_t ifModifiedSince = -1, ifNotModifiedSince = -1;
- const char *ifMatch = 0, *ifNotMatch = 0;
- uint64_t startByte = 0, byteCount = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- filename = &(param[FILENAME_PREFIX_LEN]);
- }
- else if (!strncmp(param, IF_MODIFIED_SINCE_PREFIX,
- IF_MODIFIED_SINCE_PREFIX_LEN)) {
- // Parse ifModifiedSince
- ifModifiedSince = parseIso8601Time
- (&(param[IF_MODIFIED_SINCE_PREFIX_LEN]));
- if (ifModifiedSince < 0) {
- fprintf(stderr, "\nERROR: Invalid ifModifiedSince time "
- "value; ISO 8601 time format required\n");
- usageExit(stderr);
- }
- }
- else if (!strncmp(param, IF_NOT_MODIFIED_SINCE_PREFIX,
- IF_NOT_MODIFIED_SINCE_PREFIX_LEN)) {
- // Parse ifModifiedSince
- ifNotModifiedSince = parseIso8601Time
- (&(param[IF_NOT_MODIFIED_SINCE_PREFIX_LEN]));
- if (ifNotModifiedSince < 0) {
- fprintf(stderr, "\nERROR: Invalid ifNotModifiedSince time "
- "value; ISO 8601 time format required\n");
- usageExit(stderr);
- }
- }
- else if (!strncmp(param, IF_MATCH_PREFIX, IF_MATCH_PREFIX_LEN)) {
- ifMatch = &(param[IF_MATCH_PREFIX_LEN]);
- }
- else if (!strncmp(param, IF_NOT_MATCH_PREFIX,
- IF_NOT_MATCH_PREFIX_LEN)) {
- ifNotMatch = &(param[IF_NOT_MATCH_PREFIX_LEN]);
- }
- else if (!strncmp(param, START_BYTE_PREFIX, START_BYTE_PREFIX_LEN)) {
- startByte = convertInt
- (&(param[START_BYTE_PREFIX_LEN]), "startByte");
- }
- else if (!strncmp(param, BYTE_COUNT_PREFIX, BYTE_COUNT_PREFIX_LEN)) {
- byteCount = convertInt
- (&(param[BYTE_COUNT_PREFIX_LEN]), "byteCount");
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- FILE *outfile = 0;
- if (filename) {
- // Stat the file, and if it doesn't exist, open it in w mode
- struct stat buf;
- if (stat(filename, &buf) == -1) {
- outfile = fopen(filename, "w" FOPEN_EXTRA_FLAGS);
- }
- else {
- // Open in r+ so that we don't truncate the file, just in case
- // there is an error and we write no bytes, we leave the file
- // unmodified
- outfile = fopen(filename, "r+" FOPEN_EXTRA_FLAGS);
- }
- if (!outfile) {
- fprintf(stderr, "\nERROR: Failed to open output file %s: ",
- filename);
- perror(0);
- exit(-1);
- }
- }
- else if (showResponsePropertiesG) {
- fprintf(stderr, "\nERROR: get -s requires a filename parameter\n");
- usageExit(stderr);
- }
- else {
- outfile = stdout;
- }
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3GetConditions getConditions =
- {
- ifModifiedSince,
- ifNotModifiedSince,
- ifMatch,
- ifNotMatch
- };
- S3GetObjectHandler getObjectHandler =
- {
- { &responsePropertiesCallback, &responseCompleteCallback },
- &getObjectDataCallback
- };
- do {
- S3_get_object(&bucketContext, key, &getConditions, startByte,
- byteCount, 0, 0, &getObjectHandler, outfile);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- printError();
- }
- fclose(outfile);
- S3_deinitialize();
- }
- // head object ---------------------------------------------------------------
- static void head_object(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket/key\n");
- usageExit(stderr);
- }
- // Head implies showing response properties
- showResponsePropertiesG = 1;
- // Split bucket/key
- char *slash = argv[optindex];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (!*slash || !*(slash + 1)) {
- fprintf(stderr, "\nERROR: Invalid bucket/key name: %s\n",
- argv[optindex]);
- usageExit(stderr);
- }
- *slash++ = 0;
- const char *bucketName = argv[optindex++];
- const char *key = slash;
- if (optindex != argc) {
- fprintf(stderr, "\nERROR: Extraneous parameter: %s\n", argv[optindex]);
- usageExit(stderr);
- }
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback,
- &responseCompleteCallback
- };
- do {
- S3_head_object(&bucketContext, key, 0, 0, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if ((statusG != S3StatusOK) &&
- (statusG != S3StatusErrorPreconditionFailed)) {
- printError();
- }
- S3_deinitialize();
- }
- // generate query string ------------------------------------------------------
- static void generate_query_string(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket[/key]\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex];
- const char *key = 0;
- // Split bucket/key
- char *slash = argv[optindex++];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (*slash) {
- *slash++ = 0;
- key = slash;
- }
- else {
- key = 0;
- }
- int expires = -1;
- const char *resource = 0;
- const char *httpMethod = "GET";
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, EXPIRES_PREFIX, EXPIRES_PREFIX_LEN)) {
- expires = parseIso8601Time(&(param[EXPIRES_PREFIX_LEN]));
- if (expires < 0) {
- fprintf(stderr, "\nERROR: Invalid expires time "
- "value; ISO 8601 time format required\n");
- usageExit(stderr);
- }
- }
- else if (!strncmp(param, RESOURCE_PREFIX, RESOURCE_PREFIX_LEN)) {
- resource = &(param[RESOURCE_PREFIX_LEN]);
- }
- else if (!strncmp(param, HTTP_METHOD_PREFIX, HTTP_METHOD_PREFIX_LEN)) {
- httpMethod = &(param[HTTP_METHOD_PREFIX_LEN]);
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- char buffer[S3_MAX_AUTHENTICATED_QUERY_STRING_SIZE];
- S3Status status = S3_generate_authenticated_query_string
- (buffer, &bucketContext, key, expires, resource, httpMethod);
- if (status != S3StatusOK) {
- printf("Failed to generate authenticated query string: %s\n",
- S3_get_status_name(status));
- }
- else {
- printf("%s\n", buffer);
- }
- S3_deinitialize();
- }
- // get acl -------------------------------------------------------------------
- void get_acl(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket[/key]\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex];
- const char *key = 0;
- // Split bucket/key
- char *slash = argv[optindex++];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (*slash) {
- *slash++ = 0;
- key = slash;
- }
- else {
- key = 0;
- }
- const char *filename = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- filename = &(param[FILENAME_PREFIX_LEN]);
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- FILE *outfile = 0;
- if (filename) {
- // Stat the file, and if it doesn't exist, open it in w mode
- struct stat buf;
- if (stat(filename, &buf) == -1) {
- outfile = fopen(filename, "w" FOPEN_EXTRA_FLAGS);
- }
- else {
- // Open in r+ so that we don't truncate the file, just in case
- // there is an error and we write no bytes, we leave the file
- // unmodified
- outfile = fopen(filename, "r+" FOPEN_EXTRA_FLAGS);
- }
- if (!outfile) {
- fprintf(stderr, "\nERROR: Failed to open output file %s: ",
- filename);
- perror(0);
- exit(-1);
- }
- }
- else if (showResponsePropertiesG) {
- fprintf(stderr, "\nERROR: getacl -s requires a filename parameter\n");
- usageExit(stderr);
- }
- else {
- outfile = stdout;
- }
- int aclGrantCount;
- S3AclGrant aclGrants[S3_MAX_ACL_GRANT_COUNT];
- char ownerId[S3_MAX_GRANTEE_USER_ID_SIZE];
- char ownerDisplayName[S3_MAX_GRANTEE_DISPLAY_NAME_SIZE];
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback,
- &responseCompleteCallback
- };
- do {
- S3_get_acl(&bucketContext, key, ownerId, ownerDisplayName,
- &aclGrantCount, aclGrants, 0,
- timeoutMsG, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG == S3StatusOK) {
- fprintf(outfile, "OwnerID %s %s\n", ownerId, ownerDisplayName);
- fprintf(outfile, "%-6s %-90s %-12s\n", " Type",
- " User Identifier",
- " Permission");
- fprintf(outfile, "------ "
- "------------------------------------------------------------"
- "------------------------------ ------------\n");
- int i;
- for (i = 0; i < aclGrantCount; i++) {
- S3AclGrant *grant = &(aclGrants[i]);
- const char *type;
- char composedId[S3_MAX_GRANTEE_USER_ID_SIZE +
- S3_MAX_GRANTEE_DISPLAY_NAME_SIZE + 16];
- const char *id;
- switch (grant->granteeType) {
- case S3GranteeTypeAmazonCustomerByEmail:
- type = "Email";
- id = grant->grantee.amazonCustomerByEmail.emailAddress;
- break;
- case S3GranteeTypeCanonicalUser:
- type = "UserID";
- snprintf(composedId, sizeof(composedId),
- "%s (%s)", grant->grantee.canonicalUser.id,
- grant->grantee.canonicalUser.displayName);
- id = composedId;
- break;
- case S3GranteeTypeAllAwsUsers:
- type = "Group";
- id = "Authenticated AWS Users";
- break;
- case S3GranteeTypeAllUsers:
- type = "Group";
- id = "All Users";
- break;
- default:
- type = "Group";
- id = "Log Delivery";
- break;
- }
- const char *perm;
- switch (grant->permission) {
- case S3PermissionRead:
- perm = "READ";
- break;
- case S3PermissionWrite:
- perm = "WRITE";
- break;
- case S3PermissionReadACP:
- perm = "READ_ACP";
- break;
- case S3PermissionWriteACP:
- perm = "WRITE_ACP";
- break;
- default:
- perm = "FULL_CONTROL";
- break;
- }
- fprintf(outfile, "%-6s %-90s %-12s\n", type, id, perm);
- }
- }
- else {
- printError();
- }
- fclose(outfile);
- S3_deinitialize();
- }
- // set acl -------------------------------------------------------------------
- void set_acl(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket[/key]\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex];
- const char *key = 0;
- // Split bucket/key
- char *slash = argv[optindex++];
- while (*slash && (*slash != '/')) {
- slash++;
- }
- if (*slash) {
- *slash++ = 0;
- key = slash;
- }
- else {
- key = 0;
- }
- const char *filename = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- filename = &(param[FILENAME_PREFIX_LEN]);
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- FILE *infile;
- if (filename) {
- if (!(infile = fopen(filename, "r" FOPEN_EXTRA_FLAGS))) {
- fprintf(stderr, "\nERROR: Failed to open input file %s: ",
- filename);
- perror(0);
- exit(-1);
- }
- }
- else {
- infile = stdin;
- }
- // Read in the complete ACL
- char aclBuf[65536];
- aclBuf[fread(aclBuf, 1, sizeof(aclBuf) - 1, infile)] = 0;
- char ownerId[S3_MAX_GRANTEE_USER_ID_SIZE];
- char ownerDisplayName[S3_MAX_GRANTEE_DISPLAY_NAME_SIZE];
- // Parse it
- int aclGrantCount;
- S3AclGrant aclGrants[S3_MAX_ACL_GRANT_COUNT];
- if (!convert_simple_acl(aclBuf, ownerId, ownerDisplayName,
- &aclGrantCount, aclGrants)) {
- fprintf(stderr, "\nERROR: Failed to parse ACLs\n");
- fclose(infile);
- exit(-1);
- }
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback,
- &responseCompleteCallback
- };
- do {
- S3_set_acl(&bucketContext, key, ownerId, ownerDisplayName,
- aclGrantCount, aclGrants, 0,
- timeoutMsG, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- printError();
- }
- fclose(infile);
- S3_deinitialize();
- }
- // get lifecycle -------------------------------------------------------------------
- void get_lifecycle(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex++];
- const char *filename = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- filename = &(param[FILENAME_PREFIX_LEN]);
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- FILE *outfile = 0;
- if (filename) {
- // Stat the file, and if it doesn't exist, open it in w mode
- struct stat buf;
- if (stat(filename, &buf) == -1) {
- outfile = fopen(filename, "w" FOPEN_EXTRA_FLAGS);
- }
- else {
- // Open in r+ so that we don't truncate the file, just in case
- // there is an error and we write no bytes, we leave the file
- // unmodified
- outfile = fopen(filename, "r+" FOPEN_EXTRA_FLAGS);
- }
- if (!outfile) {
- fprintf(stderr, "\nERROR: Failed to open output file %s: ",
- filename);
- perror(0);
- exit(-1);
- }
- }
- else if (showResponsePropertiesG) {
- fprintf(stderr, "\nERROR: getlifecycle -s requires a filename parameter\n");
- usageExit(stderr);
- }
- else {
- outfile = stdout;
- }
- char lifecycleBuffer[64 * 1024];
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback,
- &responseCompleteCallback
- };
- do {
- S3_get_lifecycle(&bucketContext,
- lifecycleBuffer, sizeof(lifecycleBuffer),
- 0, timeoutMsG, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG == S3StatusOK) {
- fprintf(outfile, "%s", lifecycleBuffer);
- }
- else {
- printError();
- }
- fclose(outfile);
- S3_deinitialize();
- }
- // set lifecycle -------------------------------------------------------------------
- void set_lifecycle(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex++];
- const char *filename = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- filename = &(param[FILENAME_PREFIX_LEN]);
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- FILE *infile;
- if (filename) {
- if (!(infile = fopen(filename, "r" FOPEN_EXTRA_FLAGS))) {
- fprintf(stderr, "\nERROR: Failed to open input file %s: ",
- filename);
- perror(0);
- exit(-1);
- }
- }
- else {
- infile = stdin;
- }
- // Read in the complete ACL
- char lifecycleBuf[65536];
- lifecycleBuf[fread(lifecycleBuf, 1, sizeof(lifecycleBuf) - 1, infile)] = 0;
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback,
- &responseCompleteCallback
- };
- do {
- S3_set_lifecycle(&bucketContext,
- lifecycleBuf,
- 0, timeoutMsG, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- printError();
- }
- fclose(infile);
- S3_deinitialize();
- }
- // get logging ----------------------------------------------------------------
- void get_logging(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex++];
- const char *filename = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- filename = &(param[FILENAME_PREFIX_LEN]);
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- FILE *outfile = 0;
- if (filename) {
- // Stat the file, and if it doesn't exist, open it in w mode
- struct stat buf;
- if (stat(filename, &buf) == -1) {
- outfile = fopen(filename, "w" FOPEN_EXTRA_FLAGS);
- }
- else {
- // Open in r+ so that we don't truncate the file, just in case
- // there is an error and we write no bytes, we leave the file
- // unmodified
- outfile = fopen(filename, "r+" FOPEN_EXTRA_FLAGS);
- }
- if (!outfile) {
- fprintf(stderr, "\nERROR: Failed to open output file %s: ",
- filename);
- perror(0);
- exit(-1);
- }
- }
- else if (showResponsePropertiesG) {
- fprintf(stderr, "\nERROR: getlogging -s requires a filename "
- "parameter\n");
- usageExit(stderr);
- }
- else {
- outfile = stdout;
- }
- int aclGrantCount;
- S3AclGrant aclGrants[S3_MAX_ACL_GRANT_COUNT];
- char targetBucket[S3_MAX_BUCKET_NAME_SIZE];
- char targetPrefix[S3_MAX_KEY_SIZE];
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback,
- &responseCompleteCallback
- };
- do {
- S3_get_server_access_logging(&bucketContext, targetBucket, targetPrefix,
- &aclGrantCount, aclGrants, 0,
- timeoutMsG,
- &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG == S3StatusOK) {
- if (targetBucket[0]) {
- printf("Target Bucket: %s\n", targetBucket);
- if (targetPrefix[0]) {
- printf("Target Prefix: %s\n", targetPrefix);
- }
- fprintf(outfile, "%-6s %-90s %-12s\n", " Type",
- " User Identifier",
- " Permission");
- fprintf(outfile, "------ "
- "---------------------------------------------------------"
- "--------------------------------- ------------\n");
- int i;
- for (i = 0; i < aclGrantCount; i++) {
- S3AclGrant *grant = &(aclGrants[i]);
- const char *type;
- char composedId[S3_MAX_GRANTEE_USER_ID_SIZE +
- S3_MAX_GRANTEE_DISPLAY_NAME_SIZE + 16];
- const char *id;
- switch (grant->granteeType) {
- case S3GranteeTypeAmazonCustomerByEmail:
- type = "Email";
- id = grant->grantee.amazonCustomerByEmail.emailAddress;
- break;
- case S3GranteeTypeCanonicalUser:
- type = "UserID";
- snprintf(composedId, sizeof(composedId),
- "%s (%s)", grant->grantee.canonicalUser.id,
- grant->grantee.canonicalUser.displayName);
- id = composedId;
- break;
- case S3GranteeTypeAllAwsUsers:
- type = "Group";
- id = "Authenticated AWS Users";
- break;
- default:
- type = "Group";
- id = "All Users";
- break;
- }
- const char *perm;
- switch (grant->permission) {
- case S3PermissionRead:
- perm = "READ";
- break;
- case S3PermissionWrite:
- perm = "WRITE";
- break;
- case S3PermissionReadACP:
- perm = "READ_ACP";
- break;
- case S3PermissionWriteACP:
- perm = "WRITE_ACP";
- break;
- default:
- perm = "FULL_CONTROL";
- break;
- }
- fprintf(outfile, "%-6s %-90s %-12s\n", type, id, perm);
- }
- }
- else {
- printf("Service logging is not enabled for this bucket.\n");
- }
- }
- else {
- printError();
- }
- fclose(outfile);
- S3_deinitialize();
- }
- // set logging ----------------------------------------------------------------
- void set_logging(int argc, char **argv, int optindex)
- {
- if (optindex == argc) {
- fprintf(stderr, "\nERROR: Missing parameter: bucket\n");
- usageExit(stderr);
- }
- const char *bucketName = argv[optindex++];
- const char *targetBucket = 0, *targetPrefix = 0, *filename = 0;
- while (optindex < argc) {
- char *param = argv[optindex++];
- if (!strncmp(param, TARGET_BUCKET_PREFIX, TARGET_BUCKET_PREFIX_LEN)) {
- targetBucket = &(param[TARGET_BUCKET_PREFIX_LEN]);
- }
- else if (!strncmp(param, TARGET_PREFIX_PREFIX,
- TARGET_PREFIX_PREFIX_LEN)) {
- targetPrefix = &(param[TARGET_PREFIX_PREFIX_LEN]);
- }
- else if (!strncmp(param, FILENAME_PREFIX, FILENAME_PREFIX_LEN)) {
- filename = &(param[FILENAME_PREFIX_LEN]);
- }
- else {
- fprintf(stderr, "\nERROR: Unknown param: %s\n", param);
- usageExit(stderr);
- }
- }
- int aclGrantCount = 0;
- S3AclGrant aclGrants[S3_MAX_ACL_GRANT_COUNT];
- if (targetBucket) {
- FILE *infile;
- if (filename) {
- if (!(infile = fopen(filename, "r" FOPEN_EXTRA_FLAGS))) {
- fprintf(stderr, "\nERROR: Failed to open input file %s: ",
- filename);
- perror(0);
- exit(-1);
- }
- }
- else {
- infile = stdin;
- }
- // Read in the complete ACL
- char aclBuf[65536];
- aclBuf[fread(aclBuf, 1, sizeof(aclBuf), infile)] = 0;
- char ownerId[S3_MAX_GRANTEE_USER_ID_SIZE];
- char ownerDisplayName[S3_MAX_GRANTEE_DISPLAY_NAME_SIZE];
- // Parse it
- if (!convert_simple_acl(aclBuf, ownerId, ownerDisplayName,
- &aclGrantCount, aclGrants)) {
- fprintf(stderr, "\nERROR: Failed to parse ACLs\n");
- fclose(infile);
- exit(-1);
- }
- fclose(infile);
- }
- S3_init();
- S3BucketContext bucketContext =
- {
- 0,
- bucketName,
- protocolG,
- uriStyleG,
- accessKeyIdG,
- secretAccessKeyG,
- 0,
- awsRegionG
- };
- S3ResponseHandler responseHandler =
- {
- &responsePropertiesCallback,
- &responseCompleteCallback
- };
- do {
- S3_set_server_access_logging(&bucketContext, targetBucket,
- targetPrefix, aclGrantCount, aclGrants,
- 0,
- timeoutMsG, &responseHandler, 0);
- } while (S3_status_is_retryable(statusG) && should_retry());
- if (statusG != S3StatusOK) {
- printError();
- }
- S3_deinitialize();
- }
- // main ----------------------------------------------------------------------
- int main(int argc, char **argv)
- {
- // Parse args
- while (1) {
- int idx = 0;
- int c = getopt_long(argc, argv, "vfhusr:t:g:", longOptionsG, &idx);
- if (c == -1) {
- // End of options
- break;
- }
- switch (c) {
- case 'f':
- forceG = 1;
- break;
- case 'h':
- uriStyleG = S3UriStyleVirtualHost;
- break;
- case 'u':
- protocolG = S3ProtocolHTTP;
- break;
- case 's':
- showResponsePropertiesG = 1;
- break;
- case 'r': {
- const char *v = optarg;
- retriesG = 0;
- while (*v) {
- retriesG *= 10;
- retriesG += *v - '0';
- v++;
- }
- }
- break;
- case 't': {
- const char *v = optarg;
- timeoutMsG = 0;
- while (*v) {
- timeoutMsG *= 10;
- timeoutMsG += *v - '0';
- v++;
- }
- }
- break;
- case 'v':
- verifyPeerG = S3_INIT_VERIFY_PEER;
- break;
- case 'g':
- awsRegionG = strdup(optarg);
- break;
- default:
- fprintf(stderr, "\nERROR: Unknown option: -%c\n", c);
- // Usage exit
- usageExit(stderr);
- }
- }
- // The first non-option argument gives the operation to perform
- if (optind == argc) {
- fprintf(stderr, "\n\nERROR: Missing argument: command\n\n");
- usageExit(stderr);
- }
- const char *command = argv[optind++];
- if (!strcmp(command, "help")) {
- fprintf(stdout, "\ns3 is a program for performing single requests "
- "to Amazon S3.\n");
- usageExit(stdout);
- }
- accessKeyIdG = getenv("S3_ACCESS_KEY_ID");
- if (!accessKeyIdG) {
- fprintf(stderr, "Missing environment variable: S3_ACCESS_KEY_ID\n");
- return -1;
- }
- secretAccessKeyG = getenv("S3_SECRET_ACCESS_KEY");
- if (!secretAccessKeyG) {
- fprintf(stderr,
- "Missing environment variable: S3_SECRET_ACCESS_KEY\n");
- return -1;
- }
- if (!strcmp(command, "list")) {
- list(argc, argv, optind);
- }
- else if (!strcmp(command, "test")) {
- test_bucket(argc, argv, optind);
- }
- else if (!strcmp(command, "create")) {
- create_bucket(argc, argv, optind);
- }
- else if (!strcmp(command, "delete")) {
- if (optind == argc) {
- fprintf(stderr,
- "\nERROR: Missing parameter: bucket or bucket/key\n");
- usageExit(stderr);
- }
- char *val = argv[optind];
- int hasSlash = 0;
- while (*val) {
- if (*val++ == '/') {
- hasSlash = 1;
- break;
- }
- }
- if (hasSlash) {
- delete_object(argc, argv, optind);
- }
- else {
- delete_bucket(argc, argv, optind);
- }
- }
- else if (!strcmp(command, "put")) {
- put_object(argc, argv, optind, NULL, NULL, 0);
- }
- else if (!strcmp(command, "copy")) {
- copy_object(argc, argv, optind);
- }
- else if (!strcmp(command, "get")) {
- get_object(argc, argv, optind);
- }
- else if (!strcmp(command, "head")) {
- head_object(argc, argv, optind);
- }
- else if (!strcmp(command, "gqs")) {
- generate_query_string(argc, argv, optind);
- }
- else if (!strcmp(command, "getacl")) {
- get_acl(argc, argv, optind);
- }
- else if (!strcmp(command, "setacl")) {
- set_acl(argc, argv, optind);
- }
- else if (!strcmp(command, "getlifecycle")) {
- get_lifecycle(argc, argv, optind);
- }
- else if (!strcmp(command, "setlifecycle")) {
- set_lifecycle(argc, argv, optind);
- }
- else if (!strcmp(command, "getlogging")) {
- get_logging(argc, argv, optind);
- }
- else if (!strcmp(command, "setlogging")) {
- set_logging(argc, argv, optind);
- }
- else if (!strcmp(command, "listmultiparts")) {
- list_multipart_uploads(argc, argv, optind);
- }
- else if (!strcmp(command, "abortmp")) {
- abort_multipart_upload(argc, argv, optind);
- }
- else if (!strcmp(command, "listparts")) {
- list_parts(argc, argv, optind);
- }
- else {
- fprintf(stderr, "Unknown command: %s\n", command);
- return -1;
- }
- return 0;
- }
|