2011-03-01 19:35:55 +00:00
|
|
|
/*
|
|
|
|
* s3fs - FUSE-based file system backed by Amazon S3
|
|
|
|
*
|
|
|
|
* Copyright 2007-2008 Randy Rizun <rrizun@gmail.com>
|
|
|
|
*
|
|
|
|
* This program is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU General Public License
|
|
|
|
* as published by the Free Software Foundation; either version 2
|
|
|
|
* of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This program 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 General Public License
|
|
|
|
* along with this program; if not, write to the Free Software
|
|
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <time.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <unistd.h>
|
2013-08-19 06:29:24 +00:00
|
|
|
#include <stdint.h>
|
2011-03-01 19:35:55 +00:00
|
|
|
#include <fcntl.h>
|
|
|
|
#include <dirent.h>
|
|
|
|
#include <errno.h>
|
|
|
|
#include <syslog.h>
|
|
|
|
#include <pthread.h>
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
#include <assert.h>
|
2011-03-01 19:35:55 +00:00
|
|
|
#include <curl/curl.h>
|
2011-08-31 20:36:40 +00:00
|
|
|
#include <openssl/bio.h>
|
|
|
|
#include <openssl/buffer.h>
|
|
|
|
#include <openssl/evp.h>
|
|
|
|
#include <openssl/hmac.h>
|
|
|
|
#include <openssl/md5.h>
|
2013-07-05 02:28:31 +00:00
|
|
|
#include <libxml/xpath.h>
|
|
|
|
#include <libxml/xpathInternals.h>
|
|
|
|
#include <libxml/tree.h>
|
2011-03-01 19:35:55 +00:00
|
|
|
#include <iostream>
|
|
|
|
#include <fstream>
|
|
|
|
#include <string>
|
|
|
|
#include <map>
|
Summary of Changes(1.63 -> 1.64)
* This new version was made for fixing big issue about directory object.
Please be careful and review new s3fs.
==========================
List of Changes
==========================
1) Fixed bugs
Fixed some memory leak and un-freed curl handle.
Fixed codes with a bug which is not found yet.
Fixed a bug that the s3fs could not update object's mtime when the s3fs had a opened file descriptor.
Please let us know a bug, when you find new bug of a memory leak.
2) Changed codes
Changed codes of s3fs_readdir() and list_bucket() etc.
Changed codes so that the get_realpath() function returned std::string.
Changed codes about exit() function. Because the exit() function is called from many fuse callback function directly, these function called fuse_exit() function and retuned with error.
Changed codes so that the case of the characters for the "x-amz-meta" response header is ignored.
3) Added a option
Added the norenameapi option for the storage compatible with S3 without copy API.
This option is subset of nocopyapi option.
Please read man page or call with --help option.
4) Object for directory
This is very big and important change.
The object of directory is changed "dir/" instead of "dir" for being compatible with other S3 client applications.
And this version understands the object of directory which is made by old version.
If the new s3fs changes the attributes or owner/group or mtime of the directory object, the s3fs automatically changes the object from old object name("dir") to new("dir/").
If you need to change old object name("dir") to new("dir/") manually, you can use shell script(mergedir.sh) in test directory.
* About the directory object name
AWS S3 allows the object name as both "dir" and "dir/".
The s3fs before this version understood only "dir" as directory object name, but old version did not understand the "dir/" object name.
The new version understands both of "dir" and "dir/" object name.
The s3fs user needs to be care for the special situation that I mentioned later.
The new version deletes old "dir" object and makes new "dir/" object, when the user operates the directory object for changing the permission or owner/group or mtime.
This operation does on background and automatically.
If you need to merge manually, you can use shell script which is mergedir.sh in test directory.
This script runs chmod/chown/touch commands after finding a directory.
Other S3 client application makes a directory object("dir/") without meta information which is needed to understand by the s3fs, this script can add meta information for a directory object.
If this script function is insufficient for you, you can read and modify the codes by yourself.
Please use the shell script carefully because of changing the object.
If you find a bug in this script, please let me know.
* Details
** The directory object made by old version
The directory object made by old version is not understood by other S3 client application.
New s3fs version was updated for keeping compatibility with other clients.
You can use the mergedir.sh in test directory for merging from old directory object("dir") to new("dir/").
The directory object name is changed from "dir" to "dir/" after the mergedir.sh is run, this changed "dir/" object is understood by other S3 clients.
This script runs chmod/chown/chgrp/touch/etc commands against the old directory object("dir"), then new s3fs merges that directory automatically.
If you need to change directory object from old to new manually, you can do it by running these commands which change the directory attributes(mode/owner/group/mtime).
** The directory object made by new version
The directory object name made by new version is "dir/".
Because the name includes "/", other S3 client applications understand it as the directory.
I tested new directory by s3cmd/tntDrive/DragonDisk/Gladinet as other S3 clients, the result was good compatibility.
You need to know that the compatibility has small problem by the difference in specifications between clients.
And you need to be careful about that the old s3fs can not understand the directory object which made by new s3fs.
You should change all s3fs which accesses same bucket.
** The directory object made by other S3 client application
Because the object is determined as a directory by the s3fs, the s3fs makes and uses special meta information which is "x-amz-meta-***" and "Content-Type" as HTTP header.
The s3fs sets and uses HTTP headers for the directory object, those headers are listed below.
Content-Type: application/x-directory
x-amz-meta-mode: <mode>
x-amz-meta-uid: <UID>
x-amz-meta-gid <GID>
x-amz-meta-mtime: <unix time of modified file>
Other S3 client application builds the directory object without attributes which is needed by the s3fs.
When the "ls" command is run on the s3fs-fuse file system which has directories/files made by other S3 clients, this result is shown below.
d--------- 1 root root 0 Feb 27 11:21 dir
---------- 1 root root 1024 Mar 14 02:15 file
Because the objects don't have meta information("x-amz-meta-mode"), it means mode=0000.
In this case, the directory object is shown only "d", because the s3fs determines the object as a directory when the object is the name with "/" or has "Content-type: application/x-directory" header.
(The s3fs sets "Content-Type: application/x-directory" to the directory object, but other S3 clients set "binary/octet-stream".)
In that result, nobody without root is allowed to operate the object.
The owner and group are "root"(UID=0) because the object doesn't have "x-amz-meta-uid/gid".
If the object doesn't have "x-amz-meta-mtime", the s3fs uses "Last-Modified" HTTP header.
Therefore the object's mtime is "Last-Modified" value.(This logic is same as old version)
It has been already explained, if you need to change the object attributes, you can do it by manually operation or mergedir.sh.
* Example of the compatibility with s3cmd etc
** Case A) Only "dir/file" object
One of case, there is only "dir/file" object without "dir/" object, that object is made by s3cmd or etc.
In this case, the response of REST API(list bucket) with "delimiter=/" parameter has "CommonPrefixes", and the "dir/" is listed in "CommonPrefixes/Prefix", but the "dir/" object is not real object.
The s3fs needs to determine this object as directory, however there is no real directory object("dir" or "dir/").
But both new s3fs and old one does NOT understand this "dir/" in "CommonPrefixes", because the s3fs fails to get meta information from "dir" or "dir/".
On this case, the result of "ls" command is shown below.
??????????? ? ? ? ? ? dir
This "dir" is not operated by anyone and any process, because the s3fs does not understand this object permission.
And "dir/file" object can not be shown and operated too.
Some other S3 clients(tntDrive/Gladinet/etc) can not understand this object as same as the s3fs.
If you need to operate "dir/file" object, you need to make the "dir/" object as a directory.
To make the "dir/" directory object, you need to do below.
Because there is already the "dir" object which is not real object, you can not make "dir/" directory.
(s3cmd does not make "dir/" object because the object name has "/".).
You should make another name directory(ex: "dir2/"), and move the "dir/file" objects to in new directory.
Last, you can rename the directory name from "dir2/" to "dir/".
** Case B) Both "dir" and "dir/file" object
This case is that there are "dir" and "dir/file" objects which were made by s3cmd/etc.
s3cmd and s3fs understand the "dir" object as normal(file) object because this object does not have meta information and a name with "/".
But the result of REST API(list bucket) has "dir/" name in "CommonPrefixes/Prefix".
The s3fs checks "dir/" and "dir" as a directory, but the "dir" object is not directory object.
(Because the new s3fs need to compatible old version, the s3fs checks a directory object in order of "dir/", "dir")
In this case, the result of "ls" command is shown below.
---------- 1 root root 0 Feb 27 02:48 dir
As a result, the "dir/file" can not be shown and operated because the "dir" object is a file.
If you determine the "dir" as a directory, you need to add mete information to the "dir" object by s3cmd.
** Case C) Both "dir" and "dir/" object
Last case is that there are "dir" and "dir/" objects which were made by other S3 clients.
(example: At first you upload a object "dir/" as a directory by new 3sfs, and you upload a object "dir" by s3cmd.)
New s3fs determines "dir/" as a directory, because the s3fs searches in oder of "dir/", "dir".
As a result, the "dir" object can not be shown and operated.
** Compatibility between S3 clients
Both new and old s3fs do not understand both "dir" and "dir/" at the same time, tntDrive and Galdinet are same as the s3fs.
If there are "dir/" and "dir" objects, the s3fs gives priority to "dir/".
But s3cmd and DragonDisk understand both objects.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@392 df820570-a93a-0410-bd06-b72b767a4274
2013-03-23 14:04:07 +00:00
|
|
|
#include <algorithm>
|
2013-05-27 02:22:47 +00:00
|
|
|
#include <list>
|
2013-07-05 02:28:31 +00:00
|
|
|
#include <vector>
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-03-30 13:37:14 +00:00
|
|
|
#include "common.h"
|
2011-03-01 19:35:55 +00:00
|
|
|
#include "curl.h"
|
2011-08-31 22:20:20 +00:00
|
|
|
#include "string_util.h"
|
2013-04-11 01:49:00 +00:00
|
|
|
#include "s3fs.h"
|
2013-05-27 02:22:47 +00:00
|
|
|
#include "s3fs_util.h"
|
2011-03-01 19:35:55 +00:00
|
|
|
|
|
|
|
using namespace std;
|
|
|
|
|
2013-04-11 01:49:00 +00:00
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Class BodyData
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
#define BODYDATA_RESIZE_APPEND_MIN (1 * 1024) // 1KB
|
|
|
|
#define BODYDATA_RESIZE_APPEND_MID (1 * 1024 * 1024) // 1MB
|
|
|
|
#define BODYDATA_RESIZE_APPEND_MAX (10 * 1024 * 1024) // 10MB
|
2013-09-14 21:50:39 +00:00
|
|
|
#define AJUST_BLOCK(bytes, block) (((bytes / block) + ((bytes % block) ? 1 : 0)) * block)
|
2013-04-11 01:49:00 +00:00
|
|
|
|
|
|
|
bool BodyData::Resize(size_t addbytes)
|
|
|
|
{
|
|
|
|
if(IsSafeSize(addbytes)){
|
|
|
|
return true;
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
|
2013-04-11 01:49:00 +00:00
|
|
|
// New size
|
2013-09-14 21:50:39 +00:00
|
|
|
size_t need_size = AJUST_BLOCK((lastpos + addbytes + 1) - bufsize, sizeof(off_t));
|
|
|
|
|
2013-04-11 01:49:00 +00:00
|
|
|
if(BODYDATA_RESIZE_APPEND_MAX < bufsize){
|
|
|
|
need_size = (BODYDATA_RESIZE_APPEND_MAX < need_size ? need_size : BODYDATA_RESIZE_APPEND_MAX);
|
|
|
|
}else if(BODYDATA_RESIZE_APPEND_MID < bufsize){
|
|
|
|
need_size = (BODYDATA_RESIZE_APPEND_MID < need_size ? need_size : BODYDATA_RESIZE_APPEND_MID);
|
|
|
|
}else if(BODYDATA_RESIZE_APPEND_MIN < bufsize){
|
|
|
|
need_size = ((bufsize * 2) < need_size ? need_size : (bufsize * 2));
|
|
|
|
}else{
|
|
|
|
need_size = (BODYDATA_RESIZE_APPEND_MIN < need_size ? need_size : BODYDATA_RESIZE_APPEND_MIN);
|
|
|
|
}
|
|
|
|
// realloc
|
2013-09-14 21:50:39 +00:00
|
|
|
char* newtext;
|
|
|
|
if(NULL == (newtext = (char*)realloc(text, (bufsize + need_size)))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNCRIT("not enough memory (realloc returned NULL)");
|
2013-09-14 21:50:39 +00:00
|
|
|
free(text);
|
|
|
|
text = NULL;
|
2013-04-11 01:49:00 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
text = newtext;
|
2013-04-11 01:49:00 +00:00
|
|
|
bufsize += need_size;
|
2013-09-14 21:50:39 +00:00
|
|
|
|
2013-04-11 01:49:00 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void BodyData::Clear(void)
|
|
|
|
{
|
|
|
|
if(text){
|
|
|
|
free(text);
|
|
|
|
text = NULL;
|
|
|
|
}
|
|
|
|
lastpos = 0;
|
|
|
|
bufsize = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool BodyData::Append(void* ptr, size_t bytes)
|
|
|
|
{
|
|
|
|
if(!ptr){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(0 == bytes){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(!Resize(bytes)){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
memcpy(&text[lastpos], ptr, bytes);
|
|
|
|
lastpos += bytes;
|
|
|
|
text[lastpos] = '\0';
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
const char* BodyData::str(void) const
|
|
|
|
{
|
|
|
|
static const char* strnull = "";
|
|
|
|
if(!text){
|
|
|
|
return strnull;
|
|
|
|
}
|
|
|
|
return text;
|
|
|
|
}
|
|
|
|
|
2013-03-30 13:37:14 +00:00
|
|
|
//-------------------------------------------------------------------
|
2013-07-05 02:28:31 +00:00
|
|
|
// Class S3fsCurl
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
#define MULTIPART_SIZE 10485760 // 10MB
|
|
|
|
#define MAX_MULTI_COPY_SOURCE_SIZE 524288000 // 500MB
|
|
|
|
|
2013-10-06 13:45:32 +00:00
|
|
|
#define IAM_EXPIRE_MERGIN (20 * 60) // update timming
|
|
|
|
#define IAM_CRED_URL "http://169.254.169.254/latest/meta-data/iam/security-credentials/"
|
|
|
|
#define IAMCRED_ACCESSKEYID "AccessKeyId"
|
|
|
|
#define IAMCRED_SECRETACCESSKEY "SecretAccessKey"
|
|
|
|
#define IAMCRED_ACCESSTOKEN "Token"
|
|
|
|
#define IAMCRED_EXPIRATION "Expiration"
|
|
|
|
#define IAMCRED_KEYCOUNT 4
|
|
|
|
|
2013-08-27 08:12:01 +00:00
|
|
|
pthread_mutex_t S3fsCurl::curl_handles_lock;
|
2013-09-14 21:50:39 +00:00
|
|
|
pthread_mutex_t S3fsCurl::curl_share_lock[SHARE_MUTEX_MAX];
|
2013-08-27 08:12:01 +00:00
|
|
|
pthread_mutex_t* S3fsCurl::crypt_mutex = NULL;
|
|
|
|
bool S3fsCurl::is_initglobal_done = false;
|
|
|
|
CURLSH* S3fsCurl::hCurlShare = NULL;
|
|
|
|
bool S3fsCurl::is_dns_cache = true; // default
|
2013-09-14 21:50:39 +00:00
|
|
|
bool S3fsCurl::is_ssl_session_cache= true; // default
|
2013-08-27 08:12:01 +00:00
|
|
|
long S3fsCurl::connect_timeout = 10; // default
|
|
|
|
time_t S3fsCurl::readwrite_timeout = 30; // default
|
|
|
|
int S3fsCurl::retries = 3; // default
|
|
|
|
bool S3fsCurl::is_public_bucket = false;
|
|
|
|
string S3fsCurl::default_acl = "private";
|
|
|
|
bool S3fsCurl::is_use_rrs = false;
|
|
|
|
bool S3fsCurl::is_use_sse = false;
|
|
|
|
bool S3fsCurl::is_content_md5 = false;
|
|
|
|
bool S3fsCurl::is_verbose = false;
|
|
|
|
string S3fsCurl::AWSAccessKeyId;
|
|
|
|
string S3fsCurl::AWSSecretAccessKey;
|
2013-10-06 13:45:32 +00:00
|
|
|
string S3fsCurl::AWSAccessToken;
|
|
|
|
time_t S3fsCurl::AWSAccessTokenExpire= 0;
|
|
|
|
string S3fsCurl::IAM_role;
|
2013-08-27 08:12:01 +00:00
|
|
|
long S3fsCurl::ssl_verify_hostname = 1; // default(original code...)
|
|
|
|
const EVP_MD* S3fsCurl::evp_md = EVP_sha1();
|
|
|
|
curltime_t S3fsCurl::curl_times;
|
|
|
|
curlprogress_t S3fsCurl::curl_progress;
|
|
|
|
string S3fsCurl::curl_ca_bundle;
|
|
|
|
mimes_t S3fsCurl::mimeTypes;
|
|
|
|
int S3fsCurl::max_parallel_cnt = 5; // default
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Class methods for S3fsCurl
|
2013-03-30 13:37:14 +00:00
|
|
|
//-------------------------------------------------------------------
|
2013-08-27 08:12:01 +00:00
|
|
|
bool S3fsCurl::InitS3fsCurl(const char* MimeFile)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-08-27 08:12:01 +00:00
|
|
|
if(0 != pthread_mutex_init(&S3fsCurl::curl_handles_lock, NULL)){
|
|
|
|
return false;
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
if(0 != pthread_mutex_init(&S3fsCurl::curl_share_lock[SHARE_MUTEX_DNS], NULL)){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(0 != pthread_mutex_init(&S3fsCurl::curl_share_lock[SHARE_MUTEX_SSL_SESSION], NULL)){
|
2013-08-27 08:12:01 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(!S3fsCurl::InitMimeType(MimeFile)){
|
|
|
|
return false;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
if(!S3fsCurl::InitGlobalCurl()){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(!S3fsCurl::InitShareCurl()){
|
|
|
|
return false;
|
|
|
|
}
|
2013-08-27 08:12:01 +00:00
|
|
|
if(!S3fsCurl::InitCryptMutex()){
|
|
|
|
return false;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
return true;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2011-08-31 22:20:20 +00:00
|
|
|
|
2013-08-27 08:12:01 +00:00
|
|
|
bool S3fsCurl::DestroyS3fsCurl(void)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-08-27 08:12:01 +00:00
|
|
|
int result = true;
|
2013-07-05 02:28:31 +00:00
|
|
|
|
2013-08-27 08:12:01 +00:00
|
|
|
if(!S3fsCurl::DestroyCryptMutex()){
|
2013-09-14 21:50:39 +00:00
|
|
|
result = false;
|
2013-08-27 08:12:01 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!S3fsCurl::DestroyShareCurl()){
|
2013-09-14 21:50:39 +00:00
|
|
|
result = false;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
if(!S3fsCurl::DestroyGlobalCurl()){
|
2013-09-14 21:50:39 +00:00
|
|
|
result = false;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
if(0 != pthread_mutex_destroy(&S3fsCurl::curl_share_lock[SHARE_MUTEX_DNS])){
|
|
|
|
result = false;
|
|
|
|
}
|
|
|
|
if(0 != pthread_mutex_destroy(&S3fsCurl::curl_share_lock[SHARE_MUTEX_SSL_SESSION])){
|
2013-08-27 08:12:01 +00:00
|
|
|
result = false;
|
|
|
|
}
|
|
|
|
if(0 != pthread_mutex_destroy(&S3fsCurl::curl_handles_lock)){
|
|
|
|
result = false;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
return result;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::InitGlobalCurl(void)
|
2013-06-01 15:31:31 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
if(S3fsCurl::is_initglobal_done){
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-01 15:31:31 +00:00
|
|
|
if(CURLE_OK != curl_global_init(CURL_GLOBAL_ALL)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("init_curl_global_all returns error.");
|
2013-06-01 15:31:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
S3fsCurl::is_initglobal_done = true;
|
2013-06-01 15:31:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::DestroyGlobalCurl(void)
|
2013-06-01 15:31:31 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!S3fsCurl::is_initglobal_done){
|
|
|
|
return false;
|
|
|
|
}
|
2013-06-01 15:31:31 +00:00
|
|
|
curl_global_cleanup();
|
2013-07-05 02:28:31 +00:00
|
|
|
S3fsCurl::is_initglobal_done = false;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::InitShareCurl(void)
|
|
|
|
{
|
|
|
|
CURLSHcode nSHCode;
|
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
if(!S3fsCurl::is_dns_cache && !S3fsCurl::is_ssl_session_cache){
|
|
|
|
DPRN("Curl does not share DNS data.");
|
|
|
|
return true;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
if(S3fsCurl::hCurlShare){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("already initiated.");
|
2013-07-05 02:28:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(NULL == (S3fsCurl::hCurlShare = curl_share_init())){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("curl_share_init failed");
|
2013-07-05 02:28:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(CURLSHE_OK != (nSHCode = curl_share_setopt(S3fsCurl::hCurlShare, CURLSHOPT_LOCKFUNC, S3fsCurl::LockCurlShare))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("curl_share_setopt(LOCKFUNC) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
2013-07-05 02:28:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(CURLSHE_OK != (nSHCode = curl_share_setopt(S3fsCurl::hCurlShare, CURLSHOPT_UNLOCKFUNC, S3fsCurl::UnlockCurlShare))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("curl_share_setopt(UNLOCKFUNC) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
2013-07-05 02:28:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
if(!S3fsCurl::is_dns_cache){
|
|
|
|
if(CURLSHE_OK != (nSHCode = curl_share_setopt(S3fsCurl::hCurlShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS))){
|
|
|
|
DPRN("curl_share_setopt(DNS) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
|
|
|
return false;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
if(!S3fsCurl::is_ssl_session_cache){
|
|
|
|
if(CURLSHE_OK != (nSHCode = curl_share_setopt(S3fsCurl::hCurlShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_SSL_SESSION))){
|
|
|
|
DPRN("curl_share_setopt(SSL SESSION) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(CURLSHE_OK != (nSHCode = curl_share_setopt(S3fsCurl::hCurlShare, CURLSHOPT_USERDATA, (void*)&S3fsCurl::curl_share_lock[0]))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("curl_share_setopt(USERDATA) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
2013-07-05 02:28:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::DestroyShareCurl(void)
|
|
|
|
{
|
|
|
|
if(!S3fsCurl::hCurlShare){
|
2013-09-14 21:50:39 +00:00
|
|
|
if(!S3fsCurl::is_dns_cache && !S3fsCurl::is_ssl_session_cache){
|
|
|
|
return true;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
DPRN("already destroy share curl.");
|
2013-07-05 02:28:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(CURLSHE_OK != curl_share_cleanup(S3fsCurl::hCurlShare)){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
S3fsCurl::hCurlShare = NULL;
|
|
|
|
return true;
|
2013-06-01 15:31:31 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
void S3fsCurl::LockCurlShare(CURL* handle, curl_lock_data nLockData, curl_lock_access laccess, void* useptr)
|
2013-05-22 08:49:23 +00:00
|
|
|
{
|
2013-09-14 21:50:39 +00:00
|
|
|
if(!hCurlShare){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pthread_mutex_t* lockmutex = static_cast<pthread_mutex_t*>(useptr);
|
|
|
|
if(CURL_LOCK_DATA_DNS == nLockData){
|
|
|
|
pthread_mutex_lock(&lockmutex[SHARE_MUTEX_DNS]);
|
|
|
|
}else if(CURL_LOCK_DATA_SSL_SESSION == nLockData){
|
|
|
|
pthread_mutex_lock(&lockmutex[SHARE_MUTEX_SSL_SESSION]);
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
void S3fsCurl::UnlockCurlShare(CURL* handle, curl_lock_data nLockData, void* useptr)
|
2013-05-22 08:49:23 +00:00
|
|
|
{
|
2013-09-14 21:50:39 +00:00
|
|
|
if(!hCurlShare){
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
pthread_mutex_t* lockmutex = static_cast<pthread_mutex_t*>(useptr);
|
|
|
|
if(CURL_LOCK_DATA_DNS == nLockData){
|
|
|
|
pthread_mutex_unlock(&lockmutex[SHARE_MUTEX_DNS]);
|
|
|
|
}else if(CURL_LOCK_DATA_SSL_SESSION == nLockData){
|
|
|
|
pthread_mutex_unlock(&lockmutex[SHARE_MUTEX_SSL_SESSION]);
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-27 08:12:01 +00:00
|
|
|
bool S3fsCurl::InitCryptMutex(void)
|
|
|
|
{
|
|
|
|
if(S3fsCurl::crypt_mutex){
|
|
|
|
FPRNNN("crypt_mutex is not NULL, destory it.");
|
|
|
|
if(!S3fsCurl::DestroyCryptMutex()){
|
|
|
|
DPRN("Failed to destroy crypt mutex");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(NULL == (S3fsCurl::crypt_mutex = static_cast<pthread_mutex_t*>(malloc(CRYPTO_num_locks() * sizeof(pthread_mutex_t))))){
|
|
|
|
DPRNCRIT("Could not allocate memory for crypt mutex");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
for(int cnt = 0; cnt < CRYPTO_num_locks(); cnt++){
|
|
|
|
pthread_mutex_init(&S3fsCurl::crypt_mutex[cnt], NULL);
|
|
|
|
}
|
|
|
|
// static lock
|
|
|
|
CRYPTO_set_locking_callback(S3fsCurl::CryptMutexLock);
|
|
|
|
CRYPTO_set_id_callback(S3fsCurl::CryptGetThreadid);
|
|
|
|
// dynamic lock
|
|
|
|
CRYPTO_set_dynlock_create_callback(S3fsCurl::CreateDynCryptMutex);
|
|
|
|
CRYPTO_set_dynlock_lock_callback(S3fsCurl::DynCryptMutexLock);
|
|
|
|
CRYPTO_set_dynlock_destroy_callback(S3fsCurl::DestoryDynCryptMutex);
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::DestroyCryptMutex(void)
|
|
|
|
{
|
|
|
|
if(!S3fsCurl::crypt_mutex){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
CRYPTO_set_dynlock_destroy_callback(NULL);
|
|
|
|
CRYPTO_set_dynlock_lock_callback(NULL);
|
|
|
|
CRYPTO_set_dynlock_create_callback(NULL);
|
|
|
|
CRYPTO_set_id_callback(NULL);
|
|
|
|
CRYPTO_set_locking_callback(NULL);
|
|
|
|
|
|
|
|
for(int cnt = 0; cnt < CRYPTO_num_locks(); cnt++){
|
|
|
|
pthread_mutex_destroy(&S3fsCurl::crypt_mutex[cnt]);
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
CRYPTO_cleanup_all_ex_data();
|
2013-08-27 08:12:01 +00:00
|
|
|
free(S3fsCurl::crypt_mutex);
|
|
|
|
S3fsCurl::crypt_mutex = NULL;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void S3fsCurl::CryptMutexLock(int mode, int pos, const char* file, int line)
|
|
|
|
{
|
|
|
|
if(S3fsCurl::crypt_mutex){
|
|
|
|
if(mode & CRYPTO_LOCK){
|
|
|
|
pthread_mutex_lock(&S3fsCurl::crypt_mutex[pos]);
|
|
|
|
}else{
|
|
|
|
pthread_mutex_unlock(&S3fsCurl::crypt_mutex[pos]);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
unsigned long S3fsCurl::CryptGetThreadid(void)
|
|
|
|
{
|
|
|
|
return (unsigned long)pthread_self();
|
|
|
|
}
|
|
|
|
|
|
|
|
struct CRYPTO_dynlock_value* S3fsCurl::CreateDynCryptMutex(const char* file, int line)
|
|
|
|
{
|
|
|
|
struct CRYPTO_dynlock_value* dyndata;
|
|
|
|
|
|
|
|
if(NULL == (dyndata = (struct CRYPTO_dynlock_value*)malloc(sizeof(struct CRYPTO_dynlock_value)))){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
pthread_mutex_init(&(dyndata->dyn_mutex), NULL);
|
|
|
|
return dyndata;
|
|
|
|
}
|
|
|
|
|
|
|
|
void S3fsCurl::DynCryptMutexLock(int mode, struct CRYPTO_dynlock_value* dyndata, const char* file, int line)
|
|
|
|
{
|
|
|
|
if(dyndata){
|
|
|
|
if(mode & CRYPTO_LOCK){
|
|
|
|
pthread_mutex_lock(&(dyndata->dyn_mutex));
|
|
|
|
}else{
|
|
|
|
pthread_mutex_unlock(&(dyndata->dyn_mutex));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
void S3fsCurl::DestoryDynCryptMutex(struct CRYPTO_dynlock_value* dyndata, const char* file, int line)
|
|
|
|
{
|
|
|
|
if(dyndata){
|
|
|
|
pthread_mutex_destroy(&(dyndata->dyn_mutex));
|
|
|
|
free(dyndata);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// homegrown timeout mechanism
|
|
|
|
int S3fsCurl::CurlProgress(void *clientp, double dltotal, double dlnow, double ultotal, double ulnow)
|
2013-05-22 08:49:23 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
CURL* curl = static_cast<CURL*>(clientp);
|
|
|
|
time_t now = time(0);
|
|
|
|
progress_t p(dlnow, ulnow);
|
2013-05-22 08:49:23 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
pthread_mutex_lock(&S3fsCurl::curl_handles_lock);
|
|
|
|
|
|
|
|
// any progress?
|
|
|
|
if(p != S3fsCurl::curl_progress[curl]){
|
|
|
|
// yes!
|
|
|
|
S3fsCurl::curl_times[curl] = now;
|
|
|
|
S3fsCurl::curl_progress[curl] = p;
|
|
|
|
}else{
|
|
|
|
// timeout?
|
|
|
|
if(now - S3fsCurl::curl_times[curl] > readwrite_timeout){
|
|
|
|
pthread_mutex_unlock(&S3fsCurl::curl_handles_lock);
|
2013-08-19 06:29:24 +00:00
|
|
|
DPRN("timeout now: %jd, curl_times[curl]: %jd, readwrite_timeout: %jd",
|
|
|
|
(intmax_t)now, (intmax_t)(S3fsCurl::curl_times[curl]), (intmax_t)readwrite_timeout);
|
2013-07-05 02:28:31 +00:00
|
|
|
return CURLE_ABORTED_BY_CALLBACK;
|
|
|
|
}
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
2013-06-15 15:29:08 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
pthread_mutex_unlock(&S3fsCurl::curl_handles_lock);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::InitMimeType(const char* MimeFile)
|
|
|
|
{
|
|
|
|
if(!MimeFile){
|
|
|
|
MimeFile = "/etc/mime.types"; // default
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
string line;
|
|
|
|
ifstream MT(MimeFile);
|
|
|
|
if(MT.good()){
|
|
|
|
while(getline(MT, line)){
|
|
|
|
if(line[0]=='#'){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(line.size() == 0){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
|
|
|
|
stringstream tmp(line);
|
|
|
|
string mimeType;
|
|
|
|
tmp >> mimeType;
|
|
|
|
while(tmp){
|
|
|
|
string ext;
|
|
|
|
tmp >> ext;
|
|
|
|
if(ext.size() == 0){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
S3fsCurl::mimeTypes[ext] = mimeType;
|
|
|
|
}
|
|
|
|
}
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// @param s e.g., "index.html"
|
|
|
|
// @return e.g., "text/html"
|
|
|
|
//
|
|
|
|
string S3fsCurl::LookupMimeType(string name)
|
|
|
|
{
|
|
|
|
string result("application/octet-stream");
|
|
|
|
string::size_type last_pos = name.find_last_of('.');
|
|
|
|
string::size_type first_pos = name.find_first_of('.');
|
|
|
|
string prefix, ext, ext2;
|
|
|
|
|
|
|
|
// No dots in name, just return
|
|
|
|
if(last_pos == string::npos){
|
|
|
|
return result;
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
// extract the last extension
|
|
|
|
if(last_pos != string::npos){
|
|
|
|
ext = name.substr(1+last_pos, string::npos);
|
2013-06-15 15:29:08 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if (last_pos != string::npos) {
|
|
|
|
// one dot was found, now look for another
|
|
|
|
if (first_pos != string::npos && first_pos < last_pos) {
|
|
|
|
prefix = name.substr(0, last_pos);
|
|
|
|
// Now get the second to last file extension
|
|
|
|
string::size_type next_pos = prefix.find_last_of('.');
|
|
|
|
if (next_pos != string::npos) {
|
|
|
|
ext2 = prefix.substr(1+next_pos, string::npos);
|
|
|
|
}
|
|
|
|
}
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
// if we get here, then we have an extension (ext)
|
|
|
|
mimes_t::const_iterator iter = S3fsCurl::mimeTypes.find(ext);
|
|
|
|
// if the last extension matches a mimeType, then return
|
|
|
|
// that mime type
|
|
|
|
if (iter != S3fsCurl::mimeTypes.end()) {
|
|
|
|
result = (*iter).second;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// return with the default result if there isn't a second extension
|
|
|
|
if(first_pos == last_pos){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Didn't find a mime-type for the first extension
|
|
|
|
// Look for second extension in mimeTypes, return if found
|
|
|
|
iter = S3fsCurl::mimeTypes.find(ext2);
|
|
|
|
if (iter != S3fsCurl::mimeTypes.end()) {
|
|
|
|
result = (*iter).second;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// neither the last extension nor the second-to-last extension
|
|
|
|
// matched a mimeType, return the default mime type
|
|
|
|
return result;
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::LocateBundle(void)
|
2013-05-22 08:49:23 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
// See if environment variable CURL_CA_BUNDLE is set
|
|
|
|
// if so, check it, if it is a good path, then set the
|
|
|
|
// curl_ca_bundle variable to it
|
|
|
|
char *CURL_CA_BUNDLE;
|
2013-05-22 08:49:23 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(0 == S3fsCurl::curl_ca_bundle.size()){
|
|
|
|
CURL_CA_BUNDLE = getenv("CURL_CA_BUNDLE");
|
|
|
|
if(CURL_CA_BUNDLE != NULL) {
|
|
|
|
// check for existance and readability of the file
|
|
|
|
ifstream BF(CURL_CA_BUNDLE);
|
|
|
|
if(!BF.good()){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("%s: file specified by CURL_CA_BUNDLE environment variable is not readable", program_name.c_str());
|
2013-07-05 02:28:31 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
BF.close();
|
|
|
|
S3fsCurl::curl_ca_bundle.assign(CURL_CA_BUNDLE);
|
|
|
|
return true;
|
|
|
|
}
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
// not set via environment variable, look in likely locations
|
|
|
|
|
|
|
|
///////////////////////////////////////////
|
|
|
|
// from curl's (7.21.2) acinclude.m4 file
|
|
|
|
///////////////////////////////////////////
|
|
|
|
// dnl CURL_CHECK_CA_BUNDLE
|
|
|
|
// dnl -------------------------------------------------
|
|
|
|
// dnl Check if a default ca-bundle should be used
|
|
|
|
// dnl
|
|
|
|
// dnl regarding the paths this will scan:
|
|
|
|
// dnl /etc/ssl/certs/ca-certificates.crt Debian systems
|
|
|
|
// dnl /etc/pki/tls/certs/ca-bundle.crt Redhat and Mandriva
|
|
|
|
// dnl /usr/share/ssl/certs/ca-bundle.crt old(er) Redhat
|
|
|
|
// dnl /usr/local/share/certs/ca-root.crt FreeBSD
|
|
|
|
// dnl /etc/ssl/cert.pem OpenBSD
|
|
|
|
// dnl /etc/ssl/certs/ (ca path) SUSE
|
|
|
|
ifstream BF("/etc/pki/tls/certs/ca-bundle.crt");
|
|
|
|
if(BF.good()){
|
|
|
|
BF.close();
|
|
|
|
S3fsCurl::curl_ca_bundle.assign("/etc/pki/tls/certs/ca-bundle.crt");
|
2013-09-14 21:50:39 +00:00
|
|
|
}else{
|
|
|
|
DPRN("%s: /etc/pki/tls/certs/ca-bundle.crt is not readable", program_name.c_str());
|
|
|
|
return false;
|
2013-06-15 15:29:08 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
size_t S3fsCurl::WriteMemoryCallback(void* ptr, size_t blockSize, size_t numBlocks, void* data)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
|
|
|
BodyData* body = (BodyData*)data;
|
|
|
|
|
|
|
|
if(!body->Append(ptr, blockSize, numBlocks)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNCRIT("BodyData.Append() returned false.");
|
2013-07-05 02:28:31 +00:00
|
|
|
S3FS_FUSE_EXIT();
|
|
|
|
return -1;
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
return (blockSize * numBlocks);
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
size_t S3fsCurl::ReadCallback(void* ptr, size_t size, size_t nmemb, void* userp)
|
2013-05-22 08:49:23 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
S3fsCurl* pCurl = reinterpret_cast<S3fsCurl*>(userp);
|
|
|
|
|
|
|
|
if(1 > (size * nmemb)){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(0 >= pCurl->postdata_remaining){
|
|
|
|
return 0;
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
int copysize = std::min((int)(size * nmemb), pCurl->postdata_remaining);
|
|
|
|
memcpy(ptr, pCurl->postdata, copysize);
|
|
|
|
|
|
|
|
pCurl->postdata_remaining = (pCurl->postdata_remaining > copysize ? (pCurl->postdata_remaining - copysize) : 0);
|
|
|
|
pCurl->postdata += static_cast<size_t>(copysize);
|
|
|
|
|
|
|
|
return copysize;
|
2013-05-22 08:49:23 +00:00
|
|
|
}
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
size_t S3fsCurl::HeaderCallback(void* data, size_t blockSize, size_t numBlocks, void* userPtr)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2011-09-01 19:24:12 +00:00
|
|
|
headers_t* headers = reinterpret_cast<headers_t*>(userPtr);
|
|
|
|
string header(reinterpret_cast<char*>(data), blockSize * numBlocks);
|
|
|
|
string key;
|
|
|
|
stringstream ss(header);
|
2013-03-30 13:37:14 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(getline(ss, key, ':')){
|
Summary of Changes(1.63 -> 1.64)
* This new version was made for fixing big issue about directory object.
Please be careful and review new s3fs.
==========================
List of Changes
==========================
1) Fixed bugs
Fixed some memory leak and un-freed curl handle.
Fixed codes with a bug which is not found yet.
Fixed a bug that the s3fs could not update object's mtime when the s3fs had a opened file descriptor.
Please let us know a bug, when you find new bug of a memory leak.
2) Changed codes
Changed codes of s3fs_readdir() and list_bucket() etc.
Changed codes so that the get_realpath() function returned std::string.
Changed codes about exit() function. Because the exit() function is called from many fuse callback function directly, these function called fuse_exit() function and retuned with error.
Changed codes so that the case of the characters for the "x-amz-meta" response header is ignored.
3) Added a option
Added the norenameapi option for the storage compatible with S3 without copy API.
This option is subset of nocopyapi option.
Please read man page or call with --help option.
4) Object for directory
This is very big and important change.
The object of directory is changed "dir/" instead of "dir" for being compatible with other S3 client applications.
And this version understands the object of directory which is made by old version.
If the new s3fs changes the attributes or owner/group or mtime of the directory object, the s3fs automatically changes the object from old object name("dir") to new("dir/").
If you need to change old object name("dir") to new("dir/") manually, you can use shell script(mergedir.sh) in test directory.
* About the directory object name
AWS S3 allows the object name as both "dir" and "dir/".
The s3fs before this version understood only "dir" as directory object name, but old version did not understand the "dir/" object name.
The new version understands both of "dir" and "dir/" object name.
The s3fs user needs to be care for the special situation that I mentioned later.
The new version deletes old "dir" object and makes new "dir/" object, when the user operates the directory object for changing the permission or owner/group or mtime.
This operation does on background and automatically.
If you need to merge manually, you can use shell script which is mergedir.sh in test directory.
This script runs chmod/chown/touch commands after finding a directory.
Other S3 client application makes a directory object("dir/") without meta information which is needed to understand by the s3fs, this script can add meta information for a directory object.
If this script function is insufficient for you, you can read and modify the codes by yourself.
Please use the shell script carefully because of changing the object.
If you find a bug in this script, please let me know.
* Details
** The directory object made by old version
The directory object made by old version is not understood by other S3 client application.
New s3fs version was updated for keeping compatibility with other clients.
You can use the mergedir.sh in test directory for merging from old directory object("dir") to new("dir/").
The directory object name is changed from "dir" to "dir/" after the mergedir.sh is run, this changed "dir/" object is understood by other S3 clients.
This script runs chmod/chown/chgrp/touch/etc commands against the old directory object("dir"), then new s3fs merges that directory automatically.
If you need to change directory object from old to new manually, you can do it by running these commands which change the directory attributes(mode/owner/group/mtime).
** The directory object made by new version
The directory object name made by new version is "dir/".
Because the name includes "/", other S3 client applications understand it as the directory.
I tested new directory by s3cmd/tntDrive/DragonDisk/Gladinet as other S3 clients, the result was good compatibility.
You need to know that the compatibility has small problem by the difference in specifications between clients.
And you need to be careful about that the old s3fs can not understand the directory object which made by new s3fs.
You should change all s3fs which accesses same bucket.
** The directory object made by other S3 client application
Because the object is determined as a directory by the s3fs, the s3fs makes and uses special meta information which is "x-amz-meta-***" and "Content-Type" as HTTP header.
The s3fs sets and uses HTTP headers for the directory object, those headers are listed below.
Content-Type: application/x-directory
x-amz-meta-mode: <mode>
x-amz-meta-uid: <UID>
x-amz-meta-gid <GID>
x-amz-meta-mtime: <unix time of modified file>
Other S3 client application builds the directory object without attributes which is needed by the s3fs.
When the "ls" command is run on the s3fs-fuse file system which has directories/files made by other S3 clients, this result is shown below.
d--------- 1 root root 0 Feb 27 11:21 dir
---------- 1 root root 1024 Mar 14 02:15 file
Because the objects don't have meta information("x-amz-meta-mode"), it means mode=0000.
In this case, the directory object is shown only "d", because the s3fs determines the object as a directory when the object is the name with "/" or has "Content-type: application/x-directory" header.
(The s3fs sets "Content-Type: application/x-directory" to the directory object, but other S3 clients set "binary/octet-stream".)
In that result, nobody without root is allowed to operate the object.
The owner and group are "root"(UID=0) because the object doesn't have "x-amz-meta-uid/gid".
If the object doesn't have "x-amz-meta-mtime", the s3fs uses "Last-Modified" HTTP header.
Therefore the object's mtime is "Last-Modified" value.(This logic is same as old version)
It has been already explained, if you need to change the object attributes, you can do it by manually operation or mergedir.sh.
* Example of the compatibility with s3cmd etc
** Case A) Only "dir/file" object
One of case, there is only "dir/file" object without "dir/" object, that object is made by s3cmd or etc.
In this case, the response of REST API(list bucket) with "delimiter=/" parameter has "CommonPrefixes", and the "dir/" is listed in "CommonPrefixes/Prefix", but the "dir/" object is not real object.
The s3fs needs to determine this object as directory, however there is no real directory object("dir" or "dir/").
But both new s3fs and old one does NOT understand this "dir/" in "CommonPrefixes", because the s3fs fails to get meta information from "dir" or "dir/".
On this case, the result of "ls" command is shown below.
??????????? ? ? ? ? ? dir
This "dir" is not operated by anyone and any process, because the s3fs does not understand this object permission.
And "dir/file" object can not be shown and operated too.
Some other S3 clients(tntDrive/Gladinet/etc) can not understand this object as same as the s3fs.
If you need to operate "dir/file" object, you need to make the "dir/" object as a directory.
To make the "dir/" directory object, you need to do below.
Because there is already the "dir" object which is not real object, you can not make "dir/" directory.
(s3cmd does not make "dir/" object because the object name has "/".).
You should make another name directory(ex: "dir2/"), and move the "dir/file" objects to in new directory.
Last, you can rename the directory name from "dir2/" to "dir/".
** Case B) Both "dir" and "dir/file" object
This case is that there are "dir" and "dir/file" objects which were made by s3cmd/etc.
s3cmd and s3fs understand the "dir" object as normal(file) object because this object does not have meta information and a name with "/".
But the result of REST API(list bucket) has "dir/" name in "CommonPrefixes/Prefix".
The s3fs checks "dir/" and "dir" as a directory, but the "dir" object is not directory object.
(Because the new s3fs need to compatible old version, the s3fs checks a directory object in order of "dir/", "dir")
In this case, the result of "ls" command is shown below.
---------- 1 root root 0 Feb 27 02:48 dir
As a result, the "dir/file" can not be shown and operated because the "dir" object is a file.
If you determine the "dir" as a directory, you need to add mete information to the "dir" object by s3cmd.
** Case C) Both "dir" and "dir/" object
Last case is that there are "dir" and "dir/" objects which were made by other S3 clients.
(example: At first you upload a object "dir/" as a directory by new 3sfs, and you upload a object "dir" by s3cmd.)
New s3fs determines "dir/" as a directory, because the s3fs searches in oder of "dir/", "dir".
As a result, the "dir" object can not be shown and operated.
** Compatibility between S3 clients
Both new and old s3fs do not understand both "dir" and "dir/" at the same time, tntDrive and Galdinet are same as the s3fs.
If there are "dir/" and "dir" objects, the s3fs gives priority to "dir/".
But s3cmd and DragonDisk understand both objects.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@392 df820570-a93a-0410-bd06-b72b767a4274
2013-03-23 14:04:07 +00:00
|
|
|
// Force to lower, only "x-amz"
|
|
|
|
string lkey = key;
|
|
|
|
transform(lkey.begin(), lkey.end(), lkey.begin(), static_cast<int (*)(int)>(std::tolower));
|
|
|
|
if(lkey.substr(0, 5) == "x-amz"){
|
|
|
|
key = lkey;
|
|
|
|
}
|
2011-09-01 19:24:12 +00:00
|
|
|
string value;
|
|
|
|
getline(ss, value);
|
|
|
|
(*headers)[key] = trim(value);
|
|
|
|
}
|
|
|
|
return blockSize * numBlocks;
|
|
|
|
}
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
size_t S3fsCurl::UploadReadCallback(void* ptr, size_t size, size_t nmemb, void* userp)
|
2013-07-12 00:33:36 +00:00
|
|
|
{
|
|
|
|
S3fsCurl* pCurl = reinterpret_cast<S3fsCurl*>(userp);
|
|
|
|
|
|
|
|
if(1 > (size * nmemb)){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(-1 == pCurl->partdata.fd || 0 >= pCurl->partdata.size){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
// read size
|
|
|
|
ssize_t copysize = (size * nmemb) < (size_t)pCurl->partdata.size ? (size * nmemb) : (size_t)pCurl->partdata.size;
|
|
|
|
ssize_t readbytes;
|
|
|
|
ssize_t totalread;
|
|
|
|
// read and set
|
|
|
|
for(totalread = 0, readbytes = 0; totalread < copysize; totalread += readbytes){
|
|
|
|
readbytes = pread(pCurl->partdata.fd, &((char*)ptr)[totalread], (copysize - totalread), pCurl->partdata.startpos + totalread);
|
|
|
|
if(0 == readbytes){
|
|
|
|
// eof
|
|
|
|
break;
|
|
|
|
}else if(-1 == readbytes){
|
|
|
|
// error
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("read file error(%d).", errno);
|
2013-07-12 00:33:36 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pCurl->partdata.startpos += totalread;
|
|
|
|
pCurl->partdata.size -= totalread;
|
|
|
|
|
|
|
|
return totalread;
|
|
|
|
}
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
size_t S3fsCurl::DownloadWriteCallback(void* ptr, size_t size, size_t nmemb, void* userp)
|
|
|
|
{
|
|
|
|
S3fsCurl* pCurl = reinterpret_cast<S3fsCurl*>(userp);
|
|
|
|
|
|
|
|
if(1 > (size * nmemb)){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
if(-1 == pCurl->partdata.fd || 0 >= pCurl->partdata.size){
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
// write size
|
|
|
|
ssize_t copysize = (size * nmemb) < (size_t)pCurl->partdata.size ? (size * nmemb) : (size_t)pCurl->partdata.size;
|
|
|
|
ssize_t writebytes;
|
|
|
|
ssize_t totalwrite;
|
|
|
|
|
|
|
|
// write
|
|
|
|
for(totalwrite = 0, writebytes = 0; totalwrite < copysize; totalwrite += writebytes){
|
|
|
|
writebytes = pwrite(pCurl->partdata.fd, &((char*)ptr)[totalwrite], (copysize - totalwrite), pCurl->partdata.startpos + totalwrite);
|
|
|
|
if(0 == writebytes){
|
|
|
|
// eof?
|
|
|
|
break;
|
|
|
|
}else if(-1 == writebytes){
|
|
|
|
// error
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("write file error(%d).", errno);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
pCurl->partdata.startpos += totalwrite;
|
|
|
|
pCurl->partdata.size -= totalwrite;
|
|
|
|
|
|
|
|
return totalwrite;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::SetDnsCache(bool isCache)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
bool old = S3fsCurl::is_dns_cache;
|
|
|
|
S3fsCurl::is_dns_cache = isCache;
|
|
|
|
return old;
|
|
|
|
}
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
bool S3fsCurl::SetSslSessionCache(bool isCache)
|
|
|
|
{
|
|
|
|
bool old = S3fsCurl::is_ssl_session_cache;
|
|
|
|
S3fsCurl::is_ssl_session_cache = isCache;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
long S3fsCurl::SetConnectTimeout(long timeout)
|
|
|
|
{
|
|
|
|
long old = S3fsCurl::connect_timeout;
|
|
|
|
S3fsCurl::connect_timeout = timeout;
|
|
|
|
return old;
|
|
|
|
}
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
time_t S3fsCurl::SetReadwriteTimeout(time_t timeout)
|
|
|
|
{
|
|
|
|
time_t old = S3fsCurl::readwrite_timeout;
|
|
|
|
S3fsCurl::readwrite_timeout = timeout;
|
|
|
|
return old;
|
2011-03-01 19:35:55 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
int S3fsCurl::SetRetries(int count)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
int old = S3fsCurl::retries;
|
|
|
|
S3fsCurl::retries = count;
|
|
|
|
return old;
|
|
|
|
}
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::SetPublicBucket(bool flag)
|
|
|
|
{
|
|
|
|
bool old = S3fsCurl::is_public_bucket;
|
|
|
|
S3fsCurl::is_public_bucket = flag;
|
|
|
|
return old;
|
2011-03-01 19:35:55 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
string S3fsCurl::SetDefaultAcl(const char* acl)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
string old = S3fsCurl::default_acl;
|
|
|
|
S3fsCurl::default_acl = acl ? acl : "";
|
|
|
|
return old;
|
|
|
|
}
|
2011-08-31 22:20:20 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::SetUseRrs(bool flag)
|
|
|
|
{
|
|
|
|
bool old = S3fsCurl::is_use_rrs;
|
|
|
|
S3fsCurl::is_use_rrs = flag;
|
|
|
|
return old;
|
2011-08-31 22:20:20 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::SetUseSse(bool flag)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
bool old = S3fsCurl::is_use_sse;
|
|
|
|
S3fsCurl::is_use_sse = flag;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::SetContentMd5(bool flag)
|
|
|
|
{
|
|
|
|
bool old = S3fsCurl::is_content_md5;
|
|
|
|
S3fsCurl::is_content_md5 = flag;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
2013-08-23 16:28:50 +00:00
|
|
|
bool S3fsCurl::SetVerbose(bool flag)
|
|
|
|
{
|
|
|
|
bool old = S3fsCurl::is_verbose;
|
|
|
|
S3fsCurl::is_verbose = flag;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::SetAccessKey(const char* AccessKeyId, const char* SecretAccessKey)
|
|
|
|
{
|
|
|
|
if(!AccessKeyId || '\0' == AccessKeyId[0] || !SecretAccessKey || '\0' == SecretAccessKey[0]){
|
|
|
|
return false;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
AWSAccessKeyId = AccessKeyId;
|
|
|
|
AWSSecretAccessKey = SecretAccessKey;
|
|
|
|
return true;
|
|
|
|
}
|
2011-09-01 19:24:12 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
long S3fsCurl::SetSslVerifyHostname(long value)
|
|
|
|
{
|
|
|
|
if(0 != value && 1 != value){
|
|
|
|
return -1;
|
2011-09-01 19:24:12 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
long old = S3fsCurl::ssl_verify_hostname;
|
|
|
|
S3fsCurl::ssl_verify_hostname = value;
|
|
|
|
return old;
|
|
|
|
}
|
2011-09-01 19:24:12 +00:00
|
|
|
|
2013-10-06 13:45:32 +00:00
|
|
|
string S3fsCurl::SetIAMRole(const char* role)
|
|
|
|
{
|
|
|
|
string old = S3fsCurl::IAM_role;
|
|
|
|
S3fsCurl::IAM_role = role ? role : "";
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
int S3fsCurl::SetMaxParallelCount(int value)
|
2013-07-10 06:24:06 +00:00
|
|
|
{
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
int old = S3fsCurl::max_parallel_cnt;
|
|
|
|
S3fsCurl::max_parallel_cnt = value;
|
2013-07-10 06:24:06 +00:00
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::UploadMultipartPostCallback(S3fsCurl* s3fscurl)
|
|
|
|
{
|
|
|
|
if(!s3fscurl){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
// check etag(md5);
|
|
|
|
if(NULL == strstr(s3fscurl->headdata->str(), s3fscurl->partdata.etag.c_str())){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
s3fscurl->partdata.etaglist->at(s3fscurl->partdata.etagpos).assign(s3fscurl->partdata.etag);
|
|
|
|
s3fscurl->partdata.uploaded = true;
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
S3fsCurl* S3fsCurl::UploadMultipartPostRetryCallback(S3fsCurl* s3fscurl)
|
|
|
|
{
|
|
|
|
if(!s3fscurl){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
// parse and get part_num, upload_id.
|
|
|
|
string upload_id;
|
|
|
|
string part_num_str;
|
|
|
|
int part_num;
|
|
|
|
if(!get_keyword_value(s3fscurl->url, "uploadId", upload_id)){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
if(!get_keyword_value(s3fscurl->url, "partNumber", part_num_str)){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
part_num = atoi(part_num_str.c_str());
|
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
if(s3fscurl->retry_count >= S3fsCurl::retries){
|
|
|
|
DPRN("Over retry count(%d) limit(%s:%d).", s3fscurl->retry_count, s3fscurl->path.c_str(), part_num);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-07-10 06:24:06 +00:00
|
|
|
// duplicate request
|
2013-10-09 01:44:56 +00:00
|
|
|
S3fsCurl* newcurl = new S3fsCurl(s3fscurl->IsUseAhbe());
|
|
|
|
newcurl->partdata.etaglist = s3fscurl->partdata.etaglist;
|
|
|
|
newcurl->partdata.etagpos = s3fscurl->partdata.etagpos;
|
|
|
|
newcurl->partdata.fd = s3fscurl->partdata.fd;
|
|
|
|
newcurl->partdata.startpos = s3fscurl->b_partdata_startpos;
|
|
|
|
newcurl->partdata.size = s3fscurl->b_partdata_size;
|
|
|
|
newcurl->b_partdata_startpos = s3fscurl->b_partdata_startpos;
|
|
|
|
newcurl->b_partdata_size = s3fscurl->b_partdata_size;
|
2013-11-11 13:45:35 +00:00
|
|
|
newcurl->retry_count = s3fscurl->retry_count + 1;
|
2013-07-10 06:24:06 +00:00
|
|
|
|
|
|
|
// setup new curl object
|
2013-10-08 08:19:10 +00:00
|
|
|
if(0 != newcurl->UploadMultipartPostSetup(s3fscurl->path.c_str(), part_num, upload_id)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("Could not duplicate curl object(%s:%d).", s3fscurl->path.c_str(), part_num);
|
2013-07-10 06:24:06 +00:00
|
|
|
delete newcurl;
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
return newcurl;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse_flg)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
string upload_id;
|
|
|
|
struct stat st;
|
|
|
|
int fd2;
|
|
|
|
etaglist_t list;
|
|
|
|
off_t remaining_bytes;
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
S3fsCurl s3fscurl(true);
|
2013-07-10 06:24:06 +00:00
|
|
|
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s][fd=%d]", SAFESTRPTR(tpath), fd);
|
2013-07-10 06:24:06 +00:00
|
|
|
|
|
|
|
// duplicate fd
|
2013-09-14 21:50:39 +00:00
|
|
|
if(-1 == (fd2 = dup(fd)) || 0 != lseek(fd2, 0, SEEK_SET)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("Cloud not duplicate file discriptor(errno=%d)", errno);
|
2013-07-10 06:24:06 +00:00
|
|
|
if(-1 != fd2){
|
|
|
|
close(fd2);
|
|
|
|
}
|
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
if(-1 == fstat(fd2, &st)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("Invalid file discriptor(errno=%d)", errno);
|
2013-09-14 21:50:39 +00:00
|
|
|
close(fd2);
|
2013-07-10 06:24:06 +00:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(0 != (result = s3fscurl.PreMultipartPostRequest(tpath, meta, upload_id, ow_sse_flg))){
|
2013-09-14 21:50:39 +00:00
|
|
|
close(fd2);
|
2013-07-10 06:24:06 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
s3fscurl.DestroyCurlHandle();
|
|
|
|
|
|
|
|
// cycle through open fd, pulling off 10MB chunks at a time
|
|
|
|
for(remaining_bytes = st.st_size; 0 < remaining_bytes; ){
|
|
|
|
S3fsMultiCurl curlmulti;
|
|
|
|
int para_cnt;
|
|
|
|
off_t chunk;
|
|
|
|
|
|
|
|
// Initialize S3fsMultiCurl
|
|
|
|
curlmulti.SetSuccessCallback(S3fsCurl::UploadMultipartPostCallback);
|
|
|
|
curlmulti.SetRetryCallback(S3fsCurl::UploadMultipartPostRetryCallback);
|
|
|
|
|
|
|
|
// Loop for setup parallel upload(multipart) request.
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
for(para_cnt = 0; para_cnt < S3fsCurl::max_parallel_cnt && 0 < remaining_bytes; para_cnt++, remaining_bytes -= chunk){
|
2013-07-10 06:24:06 +00:00
|
|
|
// chunk size
|
|
|
|
chunk = remaining_bytes > MULTIPART_SIZE ? MULTIPART_SIZE : remaining_bytes;
|
|
|
|
|
|
|
|
// s3fscurl sub object
|
2013-10-09 01:44:56 +00:00
|
|
|
S3fsCurl* s3fscurl_para = new S3fsCurl(true);
|
|
|
|
s3fscurl_para->partdata.fd = fd2;
|
|
|
|
s3fscurl_para->partdata.startpos = st.st_size - remaining_bytes;
|
|
|
|
s3fscurl_para->partdata.size = chunk;
|
|
|
|
s3fscurl_para->b_partdata_startpos = s3fscurl_para->partdata.startpos;
|
|
|
|
s3fscurl_para->b_partdata_size = s3fscurl_para->partdata.size;
|
2013-07-10 06:24:06 +00:00
|
|
|
s3fscurl_para->partdata.add_etag_list(&list);
|
|
|
|
|
|
|
|
// initiate upload part for parallel
|
|
|
|
if(0 != (result = s3fscurl_para->UploadMultipartPostSetup(tpath, list.size(), upload_id))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("failed uploading part setup(%d)", result);
|
2013-09-14 21:50:39 +00:00
|
|
|
close(fd2);
|
2013-07-10 06:24:06 +00:00
|
|
|
delete s3fscurl_para;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set into parallel object
|
|
|
|
if(!curlmulti.SetS3fsCurlObject(s3fscurl_para)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("Could not make curl object into multi curl(%s).", tpath);
|
2013-09-14 21:50:39 +00:00
|
|
|
close(fd2);
|
2013-07-10 06:24:06 +00:00
|
|
|
delete s3fscurl_para;
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
return -1;
|
2013-07-10 06:24:06 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Multi request
|
|
|
|
if(0 != (result = curlmulti.Request())){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("error occuered in multi request(errno=%d).", result);
|
2013-07-10 06:24:06 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reinit for loop.
|
|
|
|
curlmulti.Clear();
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
close(fd2);
|
2013-07-10 06:24:06 +00:00
|
|
|
|
|
|
|
if(0 != (result = s3fscurl.CompleteMultipartPostRequest(tpath, upload_id, list))){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
S3fsCurl* S3fsCurl::ParallelGetObjectRetryCallback(S3fsCurl* s3fscurl)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
|
|
|
if(!s3fscurl){
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-11-11 13:45:35 +00:00
|
|
|
if(s3fscurl->retry_count >= S3fsCurl::retries){
|
|
|
|
DPRN("Over retry count(%d) limit(%s).", s3fscurl->retry_count, s3fscurl->path.c_str());
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
// duplicate request(setup new curl object)
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
S3fsCurl* newcurl = new S3fsCurl(s3fscurl->IsUseAhbe());
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
if(0 != (result = newcurl->PreGetObjectRequest(
|
|
|
|
s3fscurl->path.c_str(), s3fscurl->partdata.fd, s3fscurl->partdata.startpos, s3fscurl->partdata.size))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("failed downloading part setup(%d)", result);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
delete newcurl;
|
|
|
|
return NULL;;
|
|
|
|
}
|
2013-11-11 13:45:35 +00:00
|
|
|
newcurl->retry_count = s3fscurl->retry_count + 1;
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
return newcurl;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S3fsCurl::ParallelGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size)
|
|
|
|
{
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s][fd=%d]", SAFESTRPTR(tpath), fd);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
|
|
|
|
int result = 0;
|
|
|
|
ssize_t remaining_bytes;
|
|
|
|
|
|
|
|
// cycle through open fd, pulling off 10MB chunks at a time
|
|
|
|
for(remaining_bytes = size; 0 < remaining_bytes; ){
|
|
|
|
S3fsMultiCurl curlmulti;
|
|
|
|
int para_cnt;
|
|
|
|
off_t chunk;
|
|
|
|
|
|
|
|
// Initialize S3fsMultiCurl
|
|
|
|
//curlmulti.SetSuccessCallback(NULL); // not need to set success callback
|
|
|
|
curlmulti.SetRetryCallback(S3fsCurl::ParallelGetObjectRetryCallback);
|
|
|
|
|
|
|
|
// Loop for setup parallel upload(multipart) request.
|
|
|
|
for(para_cnt = 0; para_cnt < S3fsCurl::max_parallel_cnt && 0 < remaining_bytes; para_cnt++, remaining_bytes -= chunk){
|
|
|
|
// chunk size
|
|
|
|
chunk = remaining_bytes > MULTIPART_SIZE ? MULTIPART_SIZE : remaining_bytes;
|
|
|
|
|
|
|
|
// s3fscurl sub object
|
|
|
|
S3fsCurl* s3fscurl_para = new S3fsCurl();
|
|
|
|
if(0 != (result = s3fscurl_para->PreGetObjectRequest(tpath, fd, (start + size - remaining_bytes), chunk))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("failed downloading part setup(%d)", result);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
delete s3fscurl_para;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set into parallel object
|
|
|
|
if(!curlmulti.SetS3fsCurlObject(s3fscurl_para)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("Could not make curl object into multi curl(%s).", tpath);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
delete s3fscurl_para;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Multi request
|
|
|
|
if(0 != (result = curlmulti.Request())){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("error occuered in multi request(errno=%d).", result);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// reinit for loop.
|
|
|
|
curlmulti.Clear();
|
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-10-06 13:45:32 +00:00
|
|
|
bool S3fsCurl::ParseIAMCredentialResponse(const char* response, iamcredmap_t& keyval)
|
|
|
|
{
|
|
|
|
if(!response){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
istringstream sscred(response);
|
|
|
|
string oneline;
|
|
|
|
keyval.clear();
|
|
|
|
while(getline(sscred, oneline, '\n')){
|
|
|
|
string::size_type pos;
|
|
|
|
string key;
|
|
|
|
string val;
|
|
|
|
if(string::npos != (pos = oneline.find(IAMCRED_ACCESSKEYID))){
|
|
|
|
key = IAMCRED_ACCESSKEYID;
|
|
|
|
}else if(string::npos != (pos = oneline.find(IAMCRED_SECRETACCESSKEY))){
|
|
|
|
key = IAMCRED_SECRETACCESSKEY;
|
|
|
|
}else if(string::npos != (pos = oneline.find(IAMCRED_ACCESSTOKEN))){
|
|
|
|
key = IAMCRED_ACCESSTOKEN;
|
|
|
|
}else if(string::npos != (pos = oneline.find(IAMCRED_EXPIRATION))){
|
|
|
|
key = IAMCRED_EXPIRATION;
|
|
|
|
}else{
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(string::npos == (pos = oneline.find(':', pos + key.length()))){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(string::npos == (pos = oneline.find('\"', pos))){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
oneline = oneline.substr(pos + sizeof(char));
|
|
|
|
if(string::npos == (pos = oneline.find('\"'))){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
val = oneline.substr(0, pos);
|
|
|
|
keyval[key] = val;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::SetIAMCredentials(const char* response)
|
|
|
|
{
|
|
|
|
FPRNINFO("IAM credential response = \"%s\"", response);
|
|
|
|
|
|
|
|
iamcredmap_t keyval;
|
|
|
|
|
|
|
|
if(!ParseIAMCredentialResponse(response, keyval)){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(IAMCRED_KEYCOUNT != keyval.size()){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
S3fsCurl::AWSAccessKeyId = keyval[string(IAMCRED_ACCESSKEYID)];
|
|
|
|
S3fsCurl::AWSSecretAccessKey = keyval[string(IAMCRED_SECRETACCESSKEY)];
|
|
|
|
S3fsCurl::AWSAccessToken = keyval[string(IAMCRED_ACCESSTOKEN)];
|
|
|
|
S3fsCurl::AWSAccessTokenExpire = cvtIAMExpireStringToTime(keyval[string(IAMCRED_EXPIRATION)].c_str());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::CheckIAMCredentialUpdate(void)
|
|
|
|
{
|
|
|
|
if(0 == S3fsCurl::IAM_role.size()){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(time(NULL) + IAM_EXPIRE_MERGIN <= S3fsCurl::AWSAccessTokenExpire){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// update
|
|
|
|
S3fsCurl s3fscurl;
|
|
|
|
if(0 != s3fscurl.GetIAMCredentials()){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Methods for S3fsCurl
|
|
|
|
//-------------------------------------------------------------------
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
S3fsCurl::S3fsCurl(bool ahbe) :
|
2013-08-21 08:39:06 +00:00
|
|
|
hCurl(NULL), path(""), base_path(""), saved_path(""), url(""), requestHeaders(NULL),
|
2013-08-21 07:43:32 +00:00
|
|
|
bodydata(NULL), headdata(NULL), LastResponseCode(-1), postdata(NULL), postdata_remaining(0), is_use_ahbe(ahbe),
|
2013-11-11 13:45:35 +00:00
|
|
|
retry_count(0), b_infile(NULL), b_postdata(NULL), b_postdata_remaining(0), b_partdata_startpos(0), b_partdata_size(0)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
2013-08-21 08:39:06 +00:00
|
|
|
type = REQTYPE_UNSET;
|
2011-09-01 19:24:12 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
S3fsCurl::~S3fsCurl()
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
DestroyCurlHandle();
|
|
|
|
}
|
2013-03-30 13:37:14 +00:00
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
bool S3fsCurl::ResetHandle(void)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
|
|
|
curl_easy_reset(hCurl);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_NOSIGNAL, 1);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_FOLLOWLOCATION, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_CONNECTTIMEOUT, S3fsCurl::connect_timeout);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_NOPROGRESS, 0);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_PROGRESSFUNCTION, S3fsCurl::CurlProgress);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_PROGRESSDATA, hCurl);
|
|
|
|
// curl_easy_setopt(hCurl, CURLOPT_FORBID_REUSE, 1);
|
2013-09-14 21:50:39 +00:00
|
|
|
|
2013-10-06 13:45:32 +00:00
|
|
|
if(type != REQTYPE_IAMCRED){
|
|
|
|
// REQTYPE_IAMCRED is always HTTP
|
|
|
|
if(0 == S3fsCurl::ssl_verify_hostname){
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_SSL_VERIFYHOST, 0);
|
|
|
|
}
|
|
|
|
if(S3fsCurl::curl_ca_bundle.size() != 0){
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_CAINFO, S3fsCurl::curl_ca_bundle.c_str());
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
if((S3fsCurl::is_dns_cache || S3fsCurl::is_ssl_session_cache) && S3fsCurl::hCurlShare){
|
2013-07-05 02:28:31 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_SHARE, S3fsCurl::hCurlShare);
|
|
|
|
}
|
2013-08-23 16:28:50 +00:00
|
|
|
if(S3fsCurl::is_verbose){
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_VERBOSE, true);
|
|
|
|
}
|
2013-03-30 13:37:14 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
S3fsCurl::curl_times[hCurl] = time(0);
|
|
|
|
S3fsCurl::curl_progress[hCurl] = progress_t(-1, -1);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::CreateCurlHandle(bool force)
|
|
|
|
{
|
|
|
|
pthread_mutex_lock(&S3fsCurl::curl_handles_lock);
|
|
|
|
|
|
|
|
if(hCurl){
|
|
|
|
if(!force){
|
|
|
|
DPRN("already create handle.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(!DestroyCurlHandle()){
|
|
|
|
DPRN("could not destroy handle.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
DPRN("already has handle, so destroied it.");
|
|
|
|
}
|
|
|
|
|
|
|
|
if(NULL == (hCurl = curl_easy_init())){
|
|
|
|
DPRN("Failed to create handle.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
type = REQTYPE_UNSET;
|
|
|
|
ResetHandle();
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
pthread_mutex_unlock(&S3fsCurl::curl_handles_lock);
|
2013-03-30 13:37:14 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
return true;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::DestroyCurlHandle(void)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!hCurl){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
pthread_mutex_lock(&S3fsCurl::curl_handles_lock);
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
S3fsCurl::curl_times.erase(hCurl);
|
|
|
|
S3fsCurl::curl_progress.erase(hCurl);
|
|
|
|
curl_easy_cleanup(hCurl);
|
|
|
|
hCurl = NULL;
|
|
|
|
ClearInternalData();
|
|
|
|
|
|
|
|
pthread_mutex_unlock(&S3fsCurl::curl_handles_lock);
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsCurl::ClearInternalData(void)
|
|
|
|
{
|
|
|
|
if(hCurl){
|
|
|
|
return false;
|
2013-06-15 15:29:08 +00:00
|
|
|
}
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_UNSET;
|
2013-07-05 02:28:31 +00:00
|
|
|
path = "";
|
|
|
|
base_path = "";
|
|
|
|
saved_path= "";
|
|
|
|
url = "";
|
|
|
|
if(requestHeaders){
|
|
|
|
curl_slist_free_all(requestHeaders);
|
|
|
|
requestHeaders = NULL;
|
|
|
|
}
|
|
|
|
responseHeaders.clear();
|
|
|
|
if(bodydata){
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
}
|
|
|
|
if(headdata){
|
|
|
|
delete headdata;
|
|
|
|
headdata = NULL;
|
|
|
|
}
|
2013-08-21 07:43:32 +00:00
|
|
|
LastResponseCode = -1;
|
|
|
|
postdata = NULL;
|
|
|
|
postdata_remaining = 0;
|
2013-11-11 13:45:35 +00:00
|
|
|
retry_count = 0;
|
2013-08-21 07:43:32 +00:00
|
|
|
b_infile = NULL;
|
|
|
|
b_postdata = NULL;
|
|
|
|
b_postdata_remaining = 0;
|
|
|
|
b_partdata_startpos = 0;
|
|
|
|
b_partdata_size = 0;
|
2013-07-10 06:24:06 +00:00
|
|
|
partdata.clear();
|
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
S3FS_MALLOCTRIM(0);
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
return true;
|
|
|
|
}
|
2011-03-01 19:35:55 +00:00
|
|
|
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
bool S3fsCurl::SetUseAhbe(bool ahbe)
|
|
|
|
{
|
|
|
|
bool old = is_use_ahbe;
|
|
|
|
is_use_ahbe = ahbe;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
bool S3fsCurl::GetResponseCode(long& responseCode)
|
|
|
|
{
|
|
|
|
if(!hCurl){
|
|
|
|
return false;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
responseCode = -1;
|
|
|
|
if(CURLE_OK != curl_easy_getinfo(hCurl, CURLINFO_RESPONSE_CODE, &LastResponseCode)){
|
|
|
|
return false;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
responseCode = LastResponseCode;
|
|
|
|
return true;
|
|
|
|
}
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
//
|
|
|
|
// Reset all options for retrying
|
|
|
|
//
|
|
|
|
bool S3fsCurl::RemakeHandle(void)
|
|
|
|
{
|
|
|
|
DPRNNN("Retry request. [type=%d][url=%s][path=%s]", type, url.c_str(), path.c_str());
|
|
|
|
|
|
|
|
if(REQTYPE_UNSET == type){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// rewind file
|
|
|
|
struct stat st;
|
|
|
|
if(b_infile){
|
|
|
|
rewind(b_infile);
|
|
|
|
if(-1 == fstat(fileno(b_infile), &st)){
|
|
|
|
DPRNNN("Could not get file stat(fd=%d)", fileno(b_infile));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// reinitialize internal data
|
|
|
|
responseHeaders.clear();
|
|
|
|
if(bodydata){
|
|
|
|
bodydata->Clear();
|
|
|
|
}
|
|
|
|
if(headdata){
|
|
|
|
headdata->Clear();
|
|
|
|
}
|
|
|
|
LastResponseCode = -1;
|
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
// count up(only use for multipart)
|
|
|
|
retry_count++;
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
// set from backup
|
|
|
|
postdata = b_postdata;
|
|
|
|
postdata_remaining = b_postdata_remaining;
|
|
|
|
partdata.startpos = b_partdata_startpos;
|
|
|
|
partdata.size = b_partdata_size;
|
|
|
|
|
|
|
|
// reset handle
|
|
|
|
ResetHandle();
|
|
|
|
|
|
|
|
// set options
|
|
|
|
switch(type){
|
|
|
|
case REQTYPE_DELETE:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_HEAD:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_NOBODY, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_FILETIME, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
// responseHeaders
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERDATA, (void*)&responseHeaders);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERFUNCTION, HeaderCallback);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_PUTHEAD:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_UPLOAD, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE, 0);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_PUT:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_UPLOAD, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
if(b_infile){
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(st.st_size));
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILE, b_infile);
|
|
|
|
}else{
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE, 0);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_GET:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, S3fsCurl::DownloadWriteCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)this);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_CHKBUCKET:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_FAILONERROR, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_LISTBUCKET:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_PREMULTIPOST:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_POST, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_POSTFIELDSIZE, 0);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_COMPLETEMULTIPOST:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_POST, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
2013-09-27 07:39:07 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_POSTFIELDSIZE, static_cast<curl_off_t>(postdata_remaining));
|
2013-08-21 07:43:32 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_READDATA, (void*)this);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_READFUNCTION, S3fsCurl::ReadCallback);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_UPLOADMULTIPOST:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_UPLOAD, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERDATA, (void*)headdata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERFUNCTION, WriteMemoryCallback);
|
2013-09-27 07:39:07 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(partdata.size));
|
2013-08-21 07:43:32 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_READFUNCTION, S3fsCurl::UploadReadCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_READDATA, (void*)this);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_COPYMULTIPOST:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_UPLOAD, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERDATA, (void*)headdata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE, 0);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case REQTYPE_MULTILIST:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
break;
|
|
|
|
|
2013-10-06 13:45:32 +00:00
|
|
|
case REQTYPE_IAMCRED:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
break;
|
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
case REQTYPE_ABORTMULTIUPLOAD:
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
break;
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
default:
|
|
|
|
DPRNNN("request type is unknown(%d)", type);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
//
|
|
|
|
// returns curl return code
|
|
|
|
//
|
2013-08-21 07:43:32 +00:00
|
|
|
int S3fsCurl::RequestPerform(void)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
|
|
|
if(debug){
|
|
|
|
char* ptr_url = NULL;
|
|
|
|
curl_easy_getinfo(hCurl, CURLINFO_EFFECTIVE_URL , &ptr_url);
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("connecting to URL %s", SAFESTRPTR(ptr_url));
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2011-03-01 19:35:55 +00:00
|
|
|
|
|
|
|
// 1 attempt + retries...
|
2013-07-05 02:28:31 +00:00
|
|
|
for(int retrycnt = S3fsCurl::retries; 0 < retrycnt; retrycnt--){
|
|
|
|
// Requests
|
|
|
|
CURLcode curlCode = curl_easy_perform(hCurl);
|
|
|
|
|
|
|
|
// Check result
|
|
|
|
switch(curlCode){
|
2011-03-01 19:35:55 +00:00
|
|
|
case CURLE_OK:
|
|
|
|
// Need to look at the HTTP response code
|
2013-07-05 02:28:31 +00:00
|
|
|
if(0 != curl_easy_getinfo(hCurl, CURLINFO_RESPONSE_CODE, &LastResponseCode)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("curl_easy_getinfo failed while trying to retrieve HTTP response code");
|
2011-03-01 19:35:55 +00:00
|
|
|
return -EIO;
|
|
|
|
}
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("HTTP response code %ld", LastResponseCode);
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(400 > LastResponseCode){
|
2011-03-01 19:35:55 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(500 <= LastResponseCode){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("###HTTP response=%ld", LastResponseCode);
|
2011-03-01 19:35:55 +00:00
|
|
|
sleep(4);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Service response codes which are >= 400 && < 500
|
2013-07-05 02:28:31 +00:00
|
|
|
switch(LastResponseCode){
|
2011-03-01 19:35:55 +00:00
|
|
|
case 400:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("HTTP response code 400 was returned, returing EIO.");
|
|
|
|
DPRNINFO("Body Text: %s", (bodydata ? bodydata->str() : ""));
|
2011-03-01 19:35:55 +00:00
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
case 403:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("HTTP response code 403 was returned, returning EPERM");
|
|
|
|
DPRNINFO("Body Text: %s", (bodydata ? bodydata->str() : ""));
|
2011-08-30 19:44:26 +00:00
|
|
|
return -EPERM;
|
2011-03-01 19:35:55 +00:00
|
|
|
|
|
|
|
case 404:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("HTTP response code 404 was returned, returning ENOENT");
|
|
|
|
DPRNINFO("Body Text: %s", (bodydata ? bodydata->str() : ""));
|
2011-03-01 19:35:55 +00:00
|
|
|
return -ENOENT;
|
|
|
|
|
|
|
|
default:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("HTTP response code = %ld, returning EIO", LastResponseCode);
|
|
|
|
DPRNINFO("Body Text: %s", (bodydata ? bodydata->str() : ""));
|
2011-03-01 19:35:55 +00:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CURLE_WRITE_ERROR:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_WRITE_ERROR");
|
2011-03-01 19:35:55 +00:00
|
|
|
sleep(2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CURLE_OPERATION_TIMEDOUT:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_OPERATION_TIMEDOUT");
|
2011-03-01 19:35:55 +00:00
|
|
|
sleep(2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CURLE_COULDNT_RESOLVE_HOST:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_COULDNT_RESOLVE_HOST");
|
2011-03-01 19:35:55 +00:00
|
|
|
sleep(2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CURLE_COULDNT_CONNECT:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_COULDNT_CONNECT");
|
2011-03-01 19:35:55 +00:00
|
|
|
sleep(4);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CURLE_GOT_NOTHING:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_GOT_NOTHING");
|
2011-03-01 19:35:55 +00:00
|
|
|
sleep(4);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CURLE_ABORTED_BY_CALLBACK:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_ABORTED_BY_CALLBACK");
|
2011-03-01 19:35:55 +00:00
|
|
|
sleep(4);
|
2013-07-05 02:28:31 +00:00
|
|
|
S3fsCurl::curl_times[hCurl] = time(0);
|
2011-03-01 19:35:55 +00:00
|
|
|
break;
|
|
|
|
|
|
|
|
case CURLE_PARTIAL_FILE:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_PARTIAL_FILE");
|
2011-03-01 19:35:55 +00:00
|
|
|
sleep(4);
|
|
|
|
break;
|
|
|
|
|
2011-07-29 15:48:15 +00:00
|
|
|
case CURLE_SEND_ERROR:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_SEND_ERROR");
|
2011-07-29 15:48:15 +00:00
|
|
|
sleep(2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CURLE_RECV_ERROR:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_RECV_ERROR");
|
2011-07-29 15:48:15 +00:00
|
|
|
sleep(2);
|
|
|
|
break;
|
|
|
|
|
2011-03-01 19:35:55 +00:00
|
|
|
case CURLE_SSL_CACERT:
|
|
|
|
// try to locate cert, if successful, then set the
|
|
|
|
// option and continue
|
2013-07-05 02:28:31 +00:00
|
|
|
if(0 == S3fsCurl::curl_ca_bundle.size()){
|
|
|
|
if(!S3fsCurl::LocateBundle()){
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
break; // retry with CAINFO
|
2011-03-01 19:35:55 +00:00
|
|
|
}
|
2013-08-19 06:29:24 +00:00
|
|
|
DPRNCRIT("curlCode: %d msg: %s", curlCode, curl_easy_strerror(curlCode));
|
2011-03-01 19:35:55 +00:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
break;
|
|
|
|
|
|
|
|
#ifdef CURLE_PEER_FAILED_VERIFICATION
|
|
|
|
case CURLE_PEER_FAILED_VERIFICATION:
|
|
|
|
first_pos = bucket.find_first_of(".");
|
2013-07-05 02:28:31 +00:00
|
|
|
if(first_pos != string::npos){
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("curl returned a CURL_PEER_FAILED_VERIFICATION error");
|
|
|
|
FPRNNN("security issue found: buckets with periods in their name are incompatible with http");
|
|
|
|
FPRNNN("This check can be over-ridden by using the -o ssl_verify_hostname=0");
|
|
|
|
FPRNNN("The certificate will still be checked but the hostname will not be verified.");
|
|
|
|
FPRNNN("A more secure method would be to use a bucket name without periods.");
|
|
|
|
}else
|
2013-08-19 06:29:24 +00:00
|
|
|
DPRNNN("my_curl_easy_perform: curlCode: %d -- %s", curlCode, curl_easy_strerror(curlCode));
|
2011-03-01 19:35:55 +00:00
|
|
|
}
|
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
break;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// This should be invalid since curl option HTTP FAILONERROR is now off
|
|
|
|
case CURLE_HTTP_RETURNED_ERROR:
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### CURLE_HTTP_RETURNED_ERROR");
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(0 != curl_easy_getinfo(hCurl, CURLINFO_RESPONSE_CODE, &LastResponseCode)){
|
2011-03-01 19:35:55 +00:00
|
|
|
return -EIO;
|
|
|
|
}
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("HTTP response code =%ld", LastResponseCode);
|
2011-03-01 19:35:55 +00:00
|
|
|
|
|
|
|
// Let's try to retrieve the
|
2013-07-05 02:28:31 +00:00
|
|
|
if(404 == LastResponseCode){
|
2011-03-01 19:35:55 +00:00
|
|
|
return -ENOENT;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(500 > LastResponseCode){
|
2011-03-01 19:35:55 +00:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
|
|
|
|
// Unknown CURL return code
|
|
|
|
default:
|
2013-08-19 06:29:24 +00:00
|
|
|
DPRNCRIT("###curlCode: %d msg: %s", curlCode, curl_easy_strerror(curlCode));
|
2011-03-01 19:35:55 +00:00
|
|
|
exit(EXIT_FAILURE);
|
|
|
|
break;
|
|
|
|
}
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("### retrying...");
|
2013-08-21 07:43:32 +00:00
|
|
|
|
|
|
|
if(!RemakeHandle()){
|
|
|
|
DPRNNN("Failed to reset handle and internal data for retrying.");
|
|
|
|
return -EIO;
|
|
|
|
}
|
2011-03-01 19:35:55 +00:00
|
|
|
}
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("### giving up");
|
2011-03-01 19:35:55 +00:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
//
|
|
|
|
// Returns the Amazon AWS signature for the given parameters.
|
|
|
|
//
|
|
|
|
// @param method e.g., "GET"
|
|
|
|
// @param content_type e.g., "application/x-directory"
|
|
|
|
// @param date e.g., get_date()
|
|
|
|
// @param resource e.g., "/pub"
|
|
|
|
//
|
|
|
|
string S3fsCurl::CalcSignature(string method, string strMD5, string content_type, string date, string resource)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2011-08-31 20:36:40 +00:00
|
|
|
int ret;
|
|
|
|
int bytes_written;
|
|
|
|
int offset;
|
|
|
|
int write_attempts = 0;
|
|
|
|
string Signature;
|
|
|
|
string StringToSign;
|
2013-07-05 02:28:31 +00:00
|
|
|
|
2013-10-06 13:45:32 +00:00
|
|
|
if(0 < S3fsCurl::IAM_role.size()){
|
|
|
|
if(!S3fsCurl::CheckIAMCredentialUpdate()){
|
|
|
|
DPRN("Something error occurred in checking IAM credential.");
|
|
|
|
return Signature; // returns empty string, then it occures error.
|
|
|
|
}
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("x-amz-security-token:" + S3fsCurl::AWSAccessToken).c_str());
|
|
|
|
}
|
|
|
|
|
2011-08-31 20:36:40 +00:00
|
|
|
StringToSign += method + "\n";
|
2013-07-05 02:28:31 +00:00
|
|
|
StringToSign += strMD5 + "\n"; // md5
|
2011-08-31 20:36:40 +00:00
|
|
|
StringToSign += content_type + "\n";
|
|
|
|
StringToSign += date + "\n";
|
2013-07-05 02:28:31 +00:00
|
|
|
for(curl_slist* headers = requestHeaders; headers; headers = headers->next){
|
|
|
|
if(0 == strncmp(headers->data, "x-amz", 5)){
|
|
|
|
StringToSign += headers->data;
|
|
|
|
StringToSign += "\n";
|
|
|
|
}
|
2011-08-31 20:36:40 +00:00
|
|
|
}
|
|
|
|
StringToSign += resource;
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
const void* key = S3fsCurl::AWSSecretAccessKey.data();
|
|
|
|
int key_len = S3fsCurl::AWSSecretAccessKey.size();
|
|
|
|
const unsigned char* sdata = reinterpret_cast<const unsigned char*>(StringToSign.data());
|
|
|
|
int sdata_len = StringToSign.size();
|
2011-08-31 20:36:40 +00:00
|
|
|
unsigned char md[EVP_MAX_MD_SIZE];
|
2013-07-05 02:28:31 +00:00
|
|
|
unsigned int md_len;
|
2011-08-31 20:36:40 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
HMAC(S3fsCurl::evp_md, key, key_len, sdata, sdata_len, md, &md_len);
|
2011-08-31 20:36:40 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
BIO* b64 = BIO_new(BIO_f_base64());
|
2011-08-31 20:36:40 +00:00
|
|
|
BIO* bmem = BIO_new(BIO_s_mem());
|
2013-07-05 02:28:31 +00:00
|
|
|
b64 = BIO_push(b64, bmem);
|
2011-08-31 20:36:40 +00:00
|
|
|
|
|
|
|
offset = 0;
|
2013-07-05 02:28:31 +00:00
|
|
|
for(;;){
|
2011-08-31 20:36:40 +00:00
|
|
|
bytes_written = BIO_write(b64, &(md[offset]), md_len);
|
|
|
|
write_attempts++;
|
|
|
|
// -1 indicates that an error occurred, or a temporary error, such as
|
|
|
|
// the server is busy, occurred and we need to retry later.
|
|
|
|
// BIO_write can do a short write, this code addresses this condition
|
2013-07-05 02:28:31 +00:00
|
|
|
if(bytes_written <= 0){
|
2011-08-31 20:36:40 +00:00
|
|
|
// Indicates whether a temporary error occurred or a failure to
|
|
|
|
// complete the operation occurred
|
2013-07-05 02:28:31 +00:00
|
|
|
if((ret = BIO_should_retry(b64))){
|
2011-08-31 20:36:40 +00:00
|
|
|
// Wait until the write can be accomplished
|
2013-07-05 02:28:31 +00:00
|
|
|
if(write_attempts <= 10){
|
2011-08-31 20:36:40 +00:00
|
|
|
continue;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2011-08-31 20:36:40 +00:00
|
|
|
// Too many write attempts
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("Failure during BIO_write, returning null String");
|
2013-09-14 21:50:39 +00:00
|
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
2011-08-31 20:36:40 +00:00
|
|
|
BIO_free_all(b64);
|
|
|
|
Signature.clear();
|
|
|
|
return Signature;
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
}else{
|
2011-08-31 20:36:40 +00:00
|
|
|
// If not a retry then it is an error
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("Failure during BIO_write, returning null String");
|
2013-09-14 21:50:39 +00:00
|
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
2011-08-31 20:36:40 +00:00
|
|
|
BIO_free_all(b64);
|
|
|
|
Signature.clear();
|
|
|
|
return Signature;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// The write request succeeded in writing some Bytes
|
|
|
|
offset += bytes_written;
|
|
|
|
md_len -= bytes_written;
|
|
|
|
|
|
|
|
// If there is no more data to write, the request sending has been
|
|
|
|
// completed
|
2013-03-30 13:37:14 +00:00
|
|
|
if(md_len <= 0){
|
2011-08-31 20:36:40 +00:00
|
|
|
break;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2011-08-31 20:36:40 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Flush the data
|
|
|
|
ret = BIO_flush(b64);
|
2013-07-05 02:28:31 +00:00
|
|
|
if(ret <= 0){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("Failure during BIO_flush, returning null String");
|
2013-09-14 21:50:39 +00:00
|
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
2011-08-31 20:36:40 +00:00
|
|
|
BIO_free_all(b64);
|
|
|
|
Signature.clear();
|
|
|
|
return Signature;
|
|
|
|
}
|
|
|
|
|
|
|
|
BUF_MEM *bptr;
|
|
|
|
BIO_get_mem_ptr(b64, &bptr);
|
2013-09-14 21:50:39 +00:00
|
|
|
Signature.assign(bptr->data, bptr->length - 1);
|
2011-08-31 20:36:40 +00:00
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
2011-08-31 20:36:40 +00:00
|
|
|
BIO_free_all(b64);
|
|
|
|
|
|
|
|
return Signature;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// XML in BodyData has UploadId, Parse XML body for UploadId
|
|
|
|
bool S3fsCurl::GetUploadId(string& upload_id)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
bool result = false;
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!bodydata){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
upload_id.clear();
|
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
xmlDocPtr doc;
|
|
|
|
if(NULL == (doc = xmlReadMemory(bodydata->str(), bodydata->size(), "", NULL, 0))){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
if(NULL == doc->children){
|
|
|
|
S3FS_XMLFREEDOC(doc);
|
2013-07-05 02:28:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
for(xmlNodePtr cur_node = doc->children->children; NULL != cur_node; cur_node = cur_node->next){
|
|
|
|
// For DEBUG
|
|
|
|
// string cur_node_name(reinterpret_cast<const char *>(cur_node->name));
|
|
|
|
// printf("cur_node_name: %s\n", cur_node_name.c_str());
|
|
|
|
|
|
|
|
if(XML_ELEMENT_NODE == cur_node->type){
|
|
|
|
string elementName = reinterpret_cast<const char*>(cur_node->name);
|
|
|
|
// For DEBUG
|
|
|
|
// printf("elementName: %s\n", elementName.c_str());
|
|
|
|
|
|
|
|
if(cur_node->children){
|
|
|
|
if(XML_TEXT_NODE == cur_node->children->type){
|
|
|
|
if(elementName == "UploadId") {
|
|
|
|
upload_id = reinterpret_cast<const char *>(cur_node->children->content);
|
|
|
|
result = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2011-03-01 19:35:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
S3FS_XMLFREEDOC(doc);
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
2011-03-01 19:35:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
int S3fsCurl::DeleteRequest(const char* tpath)
|
|
|
|
{
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(!tpath){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(tpath).c_str(), resource, turl);
|
|
|
|
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Content-Type: ");
|
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("DELETE", "", "", date, resource)).c_str());
|
2011-03-01 19:35:55 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_DELETE;
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
return RequestPerform();
|
2011-03-01 19:35:55 +00:00
|
|
|
}
|
2013-03-30 13:37:14 +00:00
|
|
|
|
2013-10-06 13:45:32 +00:00
|
|
|
//
|
|
|
|
// Get AccessKeyId/SecretAccessKey/AccessToken/Expiration by IAM role,
|
|
|
|
// and Set these value to class valiable.
|
|
|
|
//
|
|
|
|
int S3fsCurl::GetIAMCredentials(void)
|
|
|
|
{
|
|
|
|
FPRNINFO("[IAM role=%s]", S3fsCurl::IAM_role.c_str());
|
|
|
|
|
|
|
|
if(0 == S3fsCurl::IAM_role.size()){
|
|
|
|
DPRN("IAM role name is empty.");
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
// at first set type for handle
|
|
|
|
type = REQTYPE_IAMCRED;
|
|
|
|
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
|
|
|
|
// url
|
|
|
|
url = string(IAM_CRED_URL) + S3fsCurl::IAM_role;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
|
|
|
|
int result = RequestPerform();
|
|
|
|
|
|
|
|
// analizing response
|
|
|
|
if(0 == result && !S3fsCurl::SetIAMCredentials(bodydata->str())){
|
|
|
|
DPRN("Something error occured, could not get IAM credential.");
|
|
|
|
}
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
//
|
|
|
|
// tpath : target path for head request
|
|
|
|
// bpath : saved into base_path
|
|
|
|
// savedpath : saved into saved_path
|
|
|
|
//
|
|
|
|
bool S3fsCurl::PreHeadRequest(const char* tpath, const char* bpath, const char* savedpath)
|
2013-05-16 02:02:55 +00:00
|
|
|
{
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNINFO("[tpath=%s][bpath=%s][save=%s]", SAFESTRPTR(tpath), SAFESTRPTR(bpath), SAFESTRPTR(savedpath));
|
2013-05-16 02:02:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!tpath){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return false;
|
2013-05-16 02:02:55 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(tpath).c_str(), resource, turl);
|
2013-05-16 02:02:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// libcurl 7.17 does deep copy of url, deep copy "stable" url
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
base_path = SAFESTRPTR(bpath);
|
|
|
|
saved_path = SAFESTRPTR(savedpath);
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
2013-05-16 02:02:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// requestHeaders
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Content-Type: ");
|
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("HEAD", "", "", date, resource)).c_str());
|
2013-05-16 02:02:55 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_NOBODY, true); // HEAD
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_FILETIME, true); // Last-Modified
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
2013-05-16 02:02:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// responseHeaders
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERDATA, (void*)&responseHeaders);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERFUNCTION, HeaderCallback);
|
2013-05-16 02:02:55 +00:00
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_HEAD;
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
return true;
|
2013-05-16 02:02:55 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
int S3fsCurl::HeadRequest(const char* tpath, headers_t& meta)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
int result;
|
2013-05-16 02:02:55 +00:00
|
|
|
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
|
2013-05-16 02:02:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!PreHeadRequest(tpath)){
|
|
|
|
return -1;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
// Requests
|
|
|
|
if(0 != (result = RequestPerform())){
|
|
|
|
return result;
|
2013-05-16 02:02:55 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
// file exists in s3
|
|
|
|
// fixme: clean this up.
|
|
|
|
meta.clear();
|
|
|
|
for(headers_t::iterator iter = responseHeaders.begin(); iter != responseHeaders.end(); ++iter){
|
|
|
|
string key = (*iter).first;
|
|
|
|
string value = (*iter).second;
|
|
|
|
if(key == "Content-Type"){
|
|
|
|
meta[key] = value;
|
|
|
|
}else if(key == "Content-Length"){
|
|
|
|
meta[key] = value;
|
|
|
|
}else if(key == "ETag"){
|
|
|
|
meta[key] = value;
|
|
|
|
}else if(key == "Last-Modified"){
|
|
|
|
meta[key] = value;
|
|
|
|
}else if(key.substr(0, 5) == "x-amz"){
|
|
|
|
meta[key] = value;
|
|
|
|
}else{
|
|
|
|
// Check for upper case
|
|
|
|
transform(key.begin(), key.end(), key.begin(), static_cast<int (*)(int)>(std::tolower));
|
|
|
|
if(key.substr(0, 5) == "x-amz"){
|
|
|
|
meta[key] = value;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return 0;
|
2013-05-16 02:02:55 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
int S3fsCurl::PutHeadRequest(const char* tpath, headers_t& meta, bool ow_sse_flg)
|
2013-05-16 02:02:55 +00:00
|
|
|
{
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
|
2013-05-16 02:02:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!tpath){
|
|
|
|
return -1;
|
2013-05-16 02:02:55 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(tpath).c_str(), resource, turl);
|
2013-05-16 02:02:55 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
|
|
|
|
// Make request headers
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
|
|
|
|
string ContentType;
|
|
|
|
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
|
|
|
|
string key = (*iter).first;
|
|
|
|
string value = (*iter).second;
|
|
|
|
if(key == "Content-Type"){
|
|
|
|
ContentType = value;
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}else if(key.substr(0,9) == "x-amz-acl"){
|
|
|
|
// not set value, but after set it.
|
|
|
|
}else if(key.substr(0,10) == "x-amz-meta"){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}else if(key == "x-amz-copy-source"){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}else if(!ow_sse_flg && key == "x-amz-server-side-encryption"){
|
|
|
|
// If ow_sse_flg is false, SSE inherit from meta.
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// "x-amz-acl", rrs, sse
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("x-amz-acl:" + S3fsCurl::default_acl).c_str());
|
|
|
|
if(S3fsCurl::is_use_rrs){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-storage-class:REDUCED_REDUNDANCY");
|
|
|
|
}
|
|
|
|
if(ow_sse_flg && S3fsCurl::is_use_sse){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption:AES256");
|
|
|
|
}
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
if(is_use_ahbe){
|
|
|
|
// set additional header by ahbe conf
|
|
|
|
requestHeaders = AdditionalHeader::get()->AddHeader(requestHeaders, tpath);
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("PUT", "", ContentType, date, resource)).c_str());
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_UPLOAD, true); // HTTP PUT
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE, 0); // Content-Length
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_PUTHEAD;
|
|
|
|
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("copying... [path=%s]", tpath);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
int result = RequestPerform();
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
|
|
|
|
return result;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
int S3fsCurl::PutRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse_flg)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
struct stat st;
|
|
|
|
FILE* file = NULL;
|
2013-07-08 01:25:11 +00:00
|
|
|
int fd2;
|
2013-03-30 13:37:14 +00:00
|
|
|
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
|
2013-03-30 13:37:14 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!tpath){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(-1 != fd){
|
2013-07-08 01:25:11 +00:00
|
|
|
// duplicate fd
|
|
|
|
if(-1 == (fd2 = dup(fd)) || -1 == fstat(fd2, &st) || 0 != lseek(fd2, 0, SEEK_SET) || NULL == (file = fdopen(fd2, "rb"))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("Could not duplicate file discriptor(errno=%d)", errno);
|
2013-07-05 02:28:31 +00:00
|
|
|
return -errno;
|
|
|
|
}
|
2013-08-21 07:43:32 +00:00
|
|
|
b_infile = file;
|
2013-07-05 02:28:31 +00:00
|
|
|
}else{
|
|
|
|
// This case is creating zero byte obejct.(calling by create_file_object())
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("create zero byte file object.");
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if(!CreateCurlHandle(true)){
|
2013-07-08 01:25:11 +00:00
|
|
|
if(file){
|
|
|
|
fclose(file);
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(tpath).c_str(), resource, turl);
|
|
|
|
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
|
|
|
|
// Make request headers
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
|
|
|
|
string strMD5;
|
|
|
|
if(-1 != fd && S3fsCurl::is_content_md5){
|
|
|
|
strMD5 = GetContentMD5(fd);
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Content-MD5: " + strMD5).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
string ContentType;
|
|
|
|
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
|
|
|
|
string key = (*iter).first;
|
|
|
|
string value = (*iter).second;
|
|
|
|
if(key == "Content-Type"){
|
|
|
|
ContentType = value;
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}else if(key.substr(0,9) == "x-amz-acl"){
|
|
|
|
// not set value, but after set it.
|
|
|
|
}else if(key.substr(0,10) == "x-amz-meta"){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}else if(!ow_sse_flg && key == "x-amz-server-side-encryption"){
|
|
|
|
// If ow_sse_flg is false, SSE inherit from meta.
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// "x-amz-acl", rrs, sse
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("x-amz-acl:" + S3fsCurl::default_acl).c_str());
|
|
|
|
if(S3fsCurl::is_use_rrs){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-storage-class:REDUCED_REDUNDANCY");
|
|
|
|
}
|
|
|
|
if(ow_sse_flg && S3fsCurl::is_use_sse){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption:AES256");
|
|
|
|
}
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
if(is_use_ahbe){
|
|
|
|
// set additional header by ahbe conf
|
|
|
|
requestHeaders = AdditionalHeader::get()->AddHeader(requestHeaders, tpath);
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("PUT", strMD5, ContentType, date, resource)).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_UPLOAD, true); // HTTP PUT
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
if(file){
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(st.st_size)); // Content-Length
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILE, file);
|
|
|
|
}else{
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE, 0); // Content-Length: 0
|
|
|
|
}
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_PUT;
|
|
|
|
|
2013-08-19 06:29:24 +00:00
|
|
|
DPRNNN("uploading... [path=%s][fd=%d][size=%jd]", tpath, fd, (intmax_t)(-1 != fd ? st.st_size : 0));
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
int result = RequestPerform();
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
2013-07-08 01:25:11 +00:00
|
|
|
if(file){
|
|
|
|
fclose(file);
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
int S3fsCurl::PreGetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
2013-08-19 06:29:24 +00:00
|
|
|
FPRNNN("[tpath=%s][start=%jd][size=%zd]", SAFESTRPTR(tpath), (intmax_t)start, size);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
if(!tpath || -1 == fd || 0 > start || 0 >= size){
|
2013-07-05 02:28:31 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(tpath).c_str(), resource, turl);
|
|
|
|
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Content-Type: ");
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
if(-1 != start && -1 != size){
|
|
|
|
string range = "Range: bytes=";
|
|
|
|
range += str(start);
|
|
|
|
range += "-";
|
|
|
|
range += str(start + size - 1);
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, range.c_str());
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("GET", "", "", date, resource)).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, S3fsCurl::DownloadWriteCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)this);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
// set info for callback func.
|
|
|
|
// (use only fd, startpos and size, other member is not used.)
|
|
|
|
partdata.clear();
|
2013-08-21 07:43:32 +00:00
|
|
|
partdata.fd = fd;
|
|
|
|
partdata.startpos = start;
|
|
|
|
partdata.size = size;
|
|
|
|
b_partdata_startpos = start;
|
|
|
|
b_partdata_size = size;
|
|
|
|
|
|
|
|
type = REQTYPE_GET;
|
2013-07-05 02:28:31 +00:00
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
int S3fsCurl::GetObjectRequest(const char* tpath, int fd, off_t start, ssize_t size)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
2013-08-19 06:29:24 +00:00
|
|
|
FPRNNN("[tpath=%s][start=%jd][size=%zd]", SAFESTRPTR(tpath), (intmax_t)start, size);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
|
|
|
|
if(!tpath){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(0 != (result = PreGetObjectRequest(tpath, fd, start, size))){
|
|
|
|
return result;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("downloading... [path=%s][fd=%d]", tpath, fd);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
|
|
|
|
result = RequestPerform();
|
|
|
|
partdata.clear();
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S3fsCurl::CheckBucket(void)
|
|
|
|
{
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("check a bucket.");
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
2013-08-20 07:16:12 +00:00
|
|
|
MakeUrlResource(get_realpath("/").c_str(), resource, turl);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
2013-08-20 07:16:12 +00:00
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = "/";
|
2013-07-05 02:28:31 +00:00
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
|
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("GET", "", "", date, resource)).c_str());
|
|
|
|
}
|
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_FAILONERROR, true);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_CHKBUCKET;
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
int result = RequestPerform();
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S3fsCurl::ListBucketRequest(const char* tpath, const char* query)
|
|
|
|
{
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(!tpath){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource("", resource, turl); // NOTICE: path is "".
|
|
|
|
if(query){
|
|
|
|
turl += "?";
|
|
|
|
turl += query;
|
|
|
|
}
|
|
|
|
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Content-Type: ");
|
|
|
|
|
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("GET", "", "", date, (resource + "/"))).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_LISTBUCKET;
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
return RequestPerform();
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// Initialize multipart upload
|
|
|
|
//
|
|
|
|
// Example :
|
|
|
|
// POST /example-object?uploads HTTP/1.1
|
|
|
|
// Host: example-bucket.s3.amazonaws.com
|
|
|
|
// Date: Mon, 1 Nov 2010 20:34:56 GMT
|
|
|
|
// Authorization: AWS VGhpcyBtZXNzYWdlIHNpZ25lZCBieSBlbHZpbmc=
|
|
|
|
//
|
|
|
|
int S3fsCurl::PreMultipartPostRequest(const char* tpath, headers_t& meta, string& upload_id, bool ow_sse_flg)
|
|
|
|
{
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(!tpath){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(tpath).c_str(), resource, turl);
|
|
|
|
|
|
|
|
turl += "?uploads";
|
|
|
|
resource += "?uploads";
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
|
|
|
|
string date = get_date();
|
|
|
|
string contype = S3fsCurl::LookupMimeType(string(tpath));
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Accept: ");
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Content-Length: ");
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Content-Type: " + contype).c_str());
|
|
|
|
|
|
|
|
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
|
|
|
|
string key = (*iter).first;
|
|
|
|
string value = (*iter).second;
|
|
|
|
|
|
|
|
if(key.substr(0,9) == "x-amz-acl"){
|
|
|
|
// not set value, but after set it.
|
|
|
|
}else if(key.substr(0,10) == "x-amz-meta"){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}else if(!ow_sse_flg && key == "x-amz-server-side-encryption"){
|
|
|
|
// If ow_sse_flg is false, SSE inherit from meta.
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// "x-amz-acl", rrs, sse
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("x-amz-acl:" + S3fsCurl::default_acl).c_str());
|
|
|
|
if(S3fsCurl::is_use_rrs){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-storage-class:REDUCED_REDUNDANCY");
|
|
|
|
}
|
|
|
|
if(ow_sse_flg && S3fsCurl::is_use_sse){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "x-amz-server-side-encryption:AES256");
|
|
|
|
}
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
if(is_use_ahbe){
|
|
|
|
// set additional header by ahbe conf
|
|
|
|
requestHeaders = AdditionalHeader::get()->AddHeader(requestHeaders, tpath);
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("POST", "", contype, date, resource)).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_POST, true); // POST
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_POSTFIELDSIZE, 0);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_PREMULTIPOST;
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// request
|
|
|
|
int result;
|
|
|
|
if(0 != (result = RequestPerform())){
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Parse XML body for UploadId
|
|
|
|
if(!S3fsCurl::GetUploadId(upload_id)){
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2013-07-10 06:24:06 +00:00
|
|
|
int S3fsCurl::CompleteMultipartPostRequest(const char* tpath, string& upload_id, etaglist_t& parts)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
2013-08-19 06:29:24 +00:00
|
|
|
FPRNNN("[tpath=%s][parts=%zu]", SAFESTRPTR(tpath), parts.size());
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(!tpath){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// make contents
|
|
|
|
string postContent;
|
|
|
|
postContent += "<CompleteMultipartUpload>\n";
|
|
|
|
for(int cnt = 0; cnt < (int)parts.size(); cnt++){
|
2013-07-10 06:24:06 +00:00
|
|
|
if(0 == parts[cnt].length()){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("%d file part is not finished uploading.", cnt + 1);
|
Changes codes for performance(part 3)
* Summay
This revision includes big change about temporary file and local cache file.
By this big change, s3fs works with good performance when s3fs opens/
closes/syncs/reads object.
I made a big change about the handling about temporary file and local cache
file to do this implementation.
* Detail
1) About temporary file(local file)
s3fs uses a temporary file on local file system when s3fs does download/
upload/open/seek object on S3.
After this revision, s3fs calls ftruncate() function when s3fs makes the
temporary file.
In this way s3fs can set a file size of precisely length without downloading.
(Notice - ftruncate function is for XSI-compliant systems, so that possibly
you have a problem on non-XSI-compliant systems.)
By this change, s3fs can download a part of a object by requesting with
"Range" http header. It seems like downloading by each block unit.
The default block(part) size is 50MB, it is caused the result which is default
parallel requests count(5) by default multipart upload size(10MB).
If you need to change this block size, you can change by new option
"fd_page_size". This option can take from 1MB(1024 * 1024) to any bytes.
So that, you have to take care about that fdcache.cpp(and fdcache.h) were
changed a lot.
2) About local cache
Local cache files which are in directory specified by "use_cache" option do
not have always all of object data.
This cause is that s3fs uses ftruncate function and reads(writes) each block
unit of a temporary file.
s3fs manages each block unit's status which are "downloaded area" or "not".
For this status, s3fs makes new temporary file in cache directory which is
specified by "use_cache" option. This status files is in a directory which is
named "<use_cache sirectory>/.<bucket_name>/".
When s3fs opens this status file, s3fs locks this file for exclusive control by
calling flock function. You need to take care about this, the status files can
not be laid on network drive(like NFS).
This revision changes about file open mode, s3fs always opens a local cache
file and each status file with writable mode.
Last, this revision adds new option "del_cache", this option means that s3fs
deletes all local cache file when s3fs starts and exits.
3) Uploading
When s3fs writes data to file descriptor through FUSE request, old s3fs
revision downloads all of the object. But new revision does not download all,
it downloads only small percial area(some block units) including writing data
area.
And when s3fs closes or flushes the file descriptor, s3fs downloads other area
which is not downloaded from server. After that, s3fs uploads all of data.
Already r456 revision has parallel upload function, then this revision with
r456 and r457 are very big change for performance.
4) Downloading
By changing a temporary file and a local cache file, when s3fs downloads a
object, it downloads only the required range(some block units).
And s3fs downloads units by parallel GET request, it is same as a case of
uploading. (Maximum parallel request count and each download size are
specified same parameters for uploading.)
In the new revision, when s3fs opens file, s3fs returns file descriptor soon.
Because s3fs only opens(makes) the file descriptor with no downloading
data. And when s3fs reads a data, s3fs downloads only some block unit
including specified area.
This result is good for performance.
5) Changes option name
The option "parallel_upload" which added at r456 is changed to new option
name as "parallel_count". This reason is this option value is not only used by
uploading object, but a uploading object also uses this option. (For a while,
you can use old option name "parallel_upload" for compatibility.)
git-svn-id: http://s3fs.googlecode.com/svn/trunk@458 df820570-a93a-0410-bd06-b72b767a4274
2013-07-23 16:01:48 +00:00
|
|
|
return -1;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
postContent += "<Part>\n";
|
|
|
|
postContent += " <PartNumber>" + IntToStr(cnt + 1) + "</PartNumber>\n";
|
2013-07-10 06:24:06 +00:00
|
|
|
postContent += " <ETag>\"" + parts[cnt] + "\"</ETag>\n";
|
2013-07-05 02:28:31 +00:00
|
|
|
postContent += "</Part>\n";
|
|
|
|
}
|
|
|
|
postContent += "</CompleteMultipartUpload>\n";
|
|
|
|
|
|
|
|
// set postdata
|
2013-08-21 07:43:32 +00:00
|
|
|
postdata = reinterpret_cast<const unsigned char*>(postContent.c_str());
|
|
|
|
b_postdata = postdata;
|
|
|
|
postdata_remaining = postContent.size(); // without null
|
|
|
|
b_postdata_remaining = postdata_remaining;
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(tpath).c_str(), resource, turl);
|
|
|
|
|
|
|
|
turl += "?uploadId=" + upload_id;
|
|
|
|
resource += "?uploadId=" + upload_id;
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Accept:");
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Content-Type:");
|
|
|
|
|
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("POST", "", "", date, resource)).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_POST, true); // POST
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
2013-09-27 07:39:07 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_POSTFIELDSIZE, static_cast<curl_off_t>(postdata_remaining));
|
2013-07-05 02:28:31 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_READDATA, (void*)this);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_READFUNCTION, S3fsCurl::ReadCallback);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_COMPLETEMULTIPOST;
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// request
|
|
|
|
int result = RequestPerform();
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
postdata = NULL;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S3fsCurl::MultipartListRequest(string& body)
|
|
|
|
{
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("list request(multipart)");
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
path = "/";
|
|
|
|
MakeUrlResource(get_realpath(path.c_str()).c_str(), resource, turl);
|
|
|
|
|
|
|
|
turl += "?uploads";
|
|
|
|
resource += "?uploads";
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Accept: ");
|
|
|
|
|
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("GET", "", "", date, resource)).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_MULTILIST;
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
int result;
|
|
|
|
if(0 == (result = RequestPerform()) && 0 < bodydata->size()){
|
|
|
|
body = bodydata->str();
|
|
|
|
}else{
|
|
|
|
body = "";
|
|
|
|
}
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
int S3fsCurl::AbortMultipartUpload(const char* tpath, string& upload_id)
|
|
|
|
{
|
|
|
|
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
|
|
|
|
|
|
|
|
if(!tpath){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(tpath).c_str(), resource, turl);
|
|
|
|
|
|
|
|
turl += "?uploadId=" + upload_id;
|
|
|
|
resource += "?uploadId=" + upload_id;
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("DELETE", "", "", date, resource)).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
|
|
|
|
type = REQTYPE_ABORTMULTIUPLOAD;
|
|
|
|
|
|
|
|
return RequestPerform();
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
//
|
|
|
|
// PUT /ObjectName?partNumber=PartNumber&uploadId=UploadId HTTP/1.1
|
|
|
|
// Host: BucketName.s3.amazonaws.com
|
|
|
|
// Date: date
|
|
|
|
// Content-Length: Size
|
|
|
|
// Authorization: Signature
|
|
|
|
//
|
|
|
|
// PUT /my-movie.m2ts?partNumber=1&uploadId=VCVsb2FkIElEIGZvciBlbZZpbmcncyBteS1tb3ZpZS5tMnRzIHVwbG9hZR HTTP/1.1
|
|
|
|
// Host: example-bucket.s3.amazonaws.com
|
|
|
|
// Date: Mon, 1 Nov 2010 20:34:56 GMT
|
|
|
|
// Content-Length: 10485760
|
|
|
|
// Content-MD5: pUNXr/BjKK5G2UKvaRRrOA==
|
|
|
|
// Authorization: AWS VGhpcyBtZXNzYWdlIHNpZ25lZGGieSRlbHZpbmc=
|
|
|
|
//
|
2013-07-12 00:33:36 +00:00
|
|
|
|
2013-07-10 06:24:06 +00:00
|
|
|
int S3fsCurl::UploadMultipartPostSetup(const char* tpath, int part_num, string& upload_id)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
2013-08-19 06:29:24 +00:00
|
|
|
FPRNNN("[tpath=%s][start=%jd][size=%zd][part=%d]", SAFESTRPTR(tpath), (intmax_t)(partdata.startpos), partdata.size, part_num);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
2013-07-12 00:33:36 +00:00
|
|
|
if(-1 == partdata.fd || -1 == partdata.startpos || -1 == partdata.size){
|
|
|
|
return -1;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
// make md5 and file pointer
|
2013-07-12 00:33:36 +00:00
|
|
|
partdata.etag = md5sum(partdata.fd, partdata.startpos, partdata.size);
|
2013-07-10 06:24:06 +00:00
|
|
|
if(partdata.etag.empty()){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("Could not make md5 for file(part %d)", part_num);
|
2013-07-05 02:28:31 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-12 00:33:36 +00:00
|
|
|
// create handle
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
2013-07-12 00:33:36 +00:00
|
|
|
|
|
|
|
// make request
|
2013-07-05 02:28:31 +00:00
|
|
|
string urlargs = "?partNumber=" + IntToStr(part_num) + "&uploadId=" + upload_id;
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(tpath).c_str(), resource, turl);
|
|
|
|
|
|
|
|
resource += urlargs;
|
|
|
|
turl += urlargs;
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = tpath;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
headdata = new BodyData();
|
|
|
|
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, "Accept: ");
|
|
|
|
|
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("PUT", "", "", date, resource)).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_UPLOAD, true); // HTTP PUT
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERDATA, (void*)headdata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERFUNCTION, WriteMemoryCallback);
|
2013-09-27 07:39:07 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE_LARGE, static_cast<curl_off_t>(partdata.size)); // Content-Length
|
2013-07-12 00:33:36 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_READFUNCTION, S3fsCurl::UploadReadCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_READDATA, (void*)this);
|
2013-07-05 02:28:31 +00:00
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_UPLOADMULTIPOST;
|
|
|
|
|
2013-07-10 06:24:06 +00:00
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S3fsCurl::UploadMultipartPostRequest(const char* tpath, int part_num, string& upload_id)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
|
2013-08-19 06:29:24 +00:00
|
|
|
FPRNNN("[tpath=%s][start=%jd][size=%zd][part=%d]", SAFESTRPTR(tpath), (intmax_t)(partdata.startpos), partdata.size, part_num);
|
2013-07-10 06:24:06 +00:00
|
|
|
|
|
|
|
// setup
|
|
|
|
if(0 != (result = S3fsCurl::UploadMultipartPostSetup(tpath, part_num, upload_id))){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// request
|
2013-07-10 06:24:06 +00:00
|
|
|
if(0 == (result = RequestPerform())){
|
|
|
|
// check etag
|
|
|
|
if(NULL != strstr(headdata->str(), partdata.etag.c_str())){
|
|
|
|
partdata.uploaded = true;
|
|
|
|
}else{
|
|
|
|
result = -1;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2013-11-11 13:45:35 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// closing
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
delete headdata;
|
|
|
|
headdata = NULL;
|
|
|
|
|
2013-07-10 06:24:06 +00:00
|
|
|
return result;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
int S3fsCurl::CopyMultipartPostRequest(const char* from, const char* to, int part_num, string& upload_id, headers_t& meta)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[from=%s][to=%s][part=%d]", SAFESTRPTR(from), SAFESTRPTR(to), part_num);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(!from || !to){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
if(!CreateCurlHandle(true)){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
string urlargs = "?partNumber=" + IntToStr(part_num) + "&uploadId=" + upload_id;
|
|
|
|
string resource;
|
|
|
|
string turl;
|
|
|
|
MakeUrlResource(get_realpath(to).c_str(), resource, turl);
|
|
|
|
|
|
|
|
resource += urlargs;
|
|
|
|
turl += urlargs;
|
|
|
|
url = prepare_url(turl.c_str());
|
|
|
|
path = to;
|
|
|
|
requestHeaders = NULL;
|
|
|
|
responseHeaders.clear();
|
|
|
|
bodydata = new BodyData();
|
|
|
|
headdata = new BodyData();
|
|
|
|
|
|
|
|
// Make request headers
|
|
|
|
string date = get_date();
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string("Date: " + date).c_str());
|
|
|
|
|
|
|
|
string ContentType;
|
|
|
|
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
|
|
|
|
string key = (*iter).first;
|
|
|
|
string value = (*iter).second;
|
|
|
|
if(key == "Content-Type"){
|
|
|
|
ContentType = value;
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}else if(key == "x-amz-copy-source"){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}else if(key == "x-amz-copy-source-range"){
|
|
|
|
requestHeaders = curl_slist_sort_insert(requestHeaders, string(key + ":" + value).c_str());
|
|
|
|
}
|
2013-11-11 13:45:35 +00:00
|
|
|
// NOTICE: x-amz-acl, x-amz-server-side-encryption is not set!
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!S3fsCurl::IsPublicBucket()){
|
|
|
|
requestHeaders = curl_slist_sort_insert(
|
|
|
|
requestHeaders,
|
|
|
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
|
|
|
CalcSignature("PUT", "", ContentType, date, resource)).c_str());
|
|
|
|
}
|
|
|
|
|
|
|
|
// setopt
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_UPLOAD, true); // HTTP PUT
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEDATA, (void*)bodydata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_WRITEFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERDATA, (void*)headdata);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HEADERFUNCTION, WriteMemoryCallback);
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_INFILESIZE, 0); // Content-Length
|
|
|
|
curl_easy_setopt(hCurl, CURLOPT_HTTPHEADER, requestHeaders);
|
|
|
|
|
2013-08-21 07:43:32 +00:00
|
|
|
type = REQTYPE_COPYMULTIPOST;
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// request
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("copying... [from=%s][to=%s][part=%d]", from, to, part_num);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
int result = RequestPerform();
|
|
|
|
if(0 == result){
|
|
|
|
const char* start_etag= strstr(bodydata->str(), "ETag");
|
|
|
|
const char* end_etag = strstr(bodydata->str(), "/ETag>");
|
2013-07-10 06:24:06 +00:00
|
|
|
|
|
|
|
partdata.etag.assign((start_etag + 11), (size_t)(end_etag - (start_etag + 11) - 7));
|
|
|
|
partdata.uploaded = true;
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
delete bodydata;
|
|
|
|
bodydata = NULL;
|
|
|
|
delete headdata;
|
|
|
|
headdata = NULL;
|
|
|
|
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
int S3fsCurl::MultipartHeadRequest(const char* tpath, off_t size, headers_t& meta)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
|
|
|
int result;
|
|
|
|
string upload_id;
|
|
|
|
off_t chunk;
|
|
|
|
off_t bytes_remaining;
|
2013-07-10 06:24:06 +00:00
|
|
|
etaglist_t list;
|
2013-07-05 02:28:31 +00:00
|
|
|
stringstream strrange;
|
|
|
|
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s]", SAFESTRPTR(tpath));
|
2013-07-05 02:28:31 +00:00
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
if(0 != (result = PreMultipartPostRequest(tpath, meta, upload_id, false))){
|
2013-07-05 02:28:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
DestroyCurlHandle();
|
|
|
|
|
|
|
|
for(bytes_remaining = size, chunk = 0; 0 < bytes_remaining; bytes_remaining -= chunk){
|
|
|
|
chunk = bytes_remaining > MAX_MULTI_COPY_SOURCE_SIZE ? MAX_MULTI_COPY_SOURCE_SIZE : bytes_remaining;
|
|
|
|
|
|
|
|
strrange << "bytes=" << (size - bytes_remaining) << "-" << (size - bytes_remaining + chunk - 1);
|
|
|
|
meta["x-amz-copy-source-range"] = strrange.str();
|
2013-11-11 13:45:35 +00:00
|
|
|
strrange.str("");
|
2013-07-05 02:28:31 +00:00
|
|
|
strrange.clear(stringstream::goodbit);
|
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
if(0 != (result = CopyMultipartPostRequest(tpath, tpath, (list.size() + 1), upload_id, meta))){
|
2013-07-05 02:28:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
2013-07-10 06:24:06 +00:00
|
|
|
list.push_back(partdata.etag);
|
2013-07-05 02:28:31 +00:00
|
|
|
DestroyCurlHandle();
|
|
|
|
}
|
|
|
|
|
|
|
|
if(0 != (result = CompleteMultipartPostRequest(tpath, upload_id, list))){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S3fsCurl::MultipartUploadRequest(const char* tpath, headers_t& meta, int fd, bool ow_sse_flg)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
string upload_id;
|
|
|
|
struct stat st;
|
|
|
|
int fd2;
|
2013-07-10 06:24:06 +00:00
|
|
|
etaglist_t list;
|
2013-07-05 02:28:31 +00:00
|
|
|
off_t remaining_bytes;
|
|
|
|
off_t chunk;
|
|
|
|
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[tpath=%s][fd=%d]", SAFESTRPTR(tpath), fd);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
// duplicate fd
|
2013-09-14 21:50:39 +00:00
|
|
|
if(-1 == (fd2 = dup(fd)) || 0 != lseek(fd2, 0, SEEK_SET)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("Cloud not duplicate file discriptor(errno=%d)", errno);
|
2013-07-05 06:36:11 +00:00
|
|
|
if(-1 != fd2){
|
|
|
|
close(fd2);
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
if(-1 == fstat(fd2, &st)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("Invalid file discriptor(errno=%d)", errno);
|
2013-09-14 21:50:39 +00:00
|
|
|
close(fd2);
|
2013-07-05 02:28:31 +00:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(0 != (result = PreMultipartPostRequest(tpath, meta, upload_id, ow_sse_flg))){
|
2013-09-14 21:50:39 +00:00
|
|
|
close(fd2);
|
2013-07-05 02:28:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
|
|
|
DestroyCurlHandle();
|
|
|
|
|
|
|
|
// cycle through open fd, pulling off 10MB chunks at a time
|
|
|
|
for(remaining_bytes = st.st_size; 0 < remaining_bytes; remaining_bytes -= chunk){
|
2013-07-10 06:24:06 +00:00
|
|
|
// chunk size
|
2013-07-05 02:28:31 +00:00
|
|
|
chunk = remaining_bytes > MULTIPART_SIZE ? MULTIPART_SIZE : remaining_bytes;
|
|
|
|
|
2013-07-12 00:33:36 +00:00
|
|
|
// set
|
2013-08-21 07:43:32 +00:00
|
|
|
partdata.fd = fd2;
|
|
|
|
partdata.startpos = st.st_size - remaining_bytes;
|
|
|
|
partdata.size = chunk;
|
|
|
|
b_partdata_startpos = partdata.startpos;
|
|
|
|
b_partdata_size = partdata.size;
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
// upload part
|
2013-07-10 06:24:06 +00:00
|
|
|
if(0 != (result = UploadMultipartPostRequest(tpath, (list.size() + 1), upload_id))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("failed uploading part(%d)", result);
|
2013-09-14 21:50:39 +00:00
|
|
|
close(fd2);
|
2013-07-05 02:28:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
2013-07-10 06:24:06 +00:00
|
|
|
list.push_back(partdata.etag);
|
2013-07-05 02:28:31 +00:00
|
|
|
DestroyCurlHandle();
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
close(fd2);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(0 != (result = CompleteMultipartPostRequest(tpath, upload_id, list))){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return 0;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
int S3fsCurl::MultipartRenameRequest(const char* from, const char* to, headers_t& meta, off_t size)
|
2013-03-30 13:37:14 +00:00
|
|
|
{
|
2013-07-05 02:28:31 +00:00
|
|
|
int result;
|
|
|
|
string upload_id;
|
|
|
|
off_t chunk;
|
|
|
|
off_t bytes_remaining;
|
2013-07-10 06:24:06 +00:00
|
|
|
etaglist_t list;
|
2013-07-05 02:28:31 +00:00
|
|
|
stringstream strrange;
|
2013-03-30 13:37:14 +00:00
|
|
|
|
2013-08-10 15:29:39 +00:00
|
|
|
FPRNNN("[from=%s][to=%s]", SAFESTRPTR(from), SAFESTRPTR(to));
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
string srcresource;
|
|
|
|
string srcurl;
|
|
|
|
MakeUrlResource(get_realpath(from).c_str(), srcresource, srcurl);
|
|
|
|
|
|
|
|
meta["Content-Type"] = S3fsCurl::LookupMimeType(string(to));
|
|
|
|
meta["x-amz-copy-source"] = srcresource;
|
|
|
|
|
|
|
|
if(0 != (result = PreMultipartPostRequest(to, meta, upload_id, false))){
|
2013-03-30 13:37:14 +00:00
|
|
|
return result;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
DestroyCurlHandle();
|
|
|
|
|
|
|
|
for(bytes_remaining = size, chunk = 0; 0 < bytes_remaining; bytes_remaining -= chunk){
|
|
|
|
chunk = bytes_remaining > MAX_MULTI_COPY_SOURCE_SIZE ? MAX_MULTI_COPY_SOURCE_SIZE : bytes_remaining;
|
|
|
|
|
|
|
|
strrange << "bytes=" << (size - bytes_remaining) << "-" << (size - bytes_remaining + chunk - 1);
|
|
|
|
meta["x-amz-copy-source-range"] = strrange.str();
|
2013-11-11 13:45:35 +00:00
|
|
|
strrange.str("");
|
2013-07-05 02:28:31 +00:00
|
|
|
strrange.clear(stringstream::goodbit);
|
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
if(0 != (result = CopyMultipartPostRequest(from, to, (list.size() + 1), upload_id, meta))){
|
2013-07-05 02:28:31 +00:00
|
|
|
return result;
|
|
|
|
}
|
2013-07-10 06:24:06 +00:00
|
|
|
list.push_back(partdata.etag);
|
2013-07-05 02:28:31 +00:00
|
|
|
DestroyCurlHandle();
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(0 != (result = CompleteMultipartPostRequest(to, upload_id, list))){
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Class S3fsMultiCurl
|
|
|
|
//-------------------------------------------------------------------
|
2013-09-14 21:50:39 +00:00
|
|
|
#define MAX_MULTI_HEADREQ 20 // default: max request count in readdir curl_multi.
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Class method for S3fsMultiCurl
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
int S3fsMultiCurl::max_multireq = MAX_MULTI_HEADREQ;
|
|
|
|
|
|
|
|
int S3fsMultiCurl::SetMaxMultiRequest(int max)
|
|
|
|
{
|
|
|
|
int old = S3fsMultiCurl::max_multireq;
|
|
|
|
S3fsMultiCurl::max_multireq= max;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// method for S3fsMultiCurl
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
S3fsMultiCurl::S3fsMultiCurl() : hMulti(NULL), SuccessCallback(NULL), RetryCallback(NULL)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
S3fsMultiCurl::~S3fsMultiCurl()
|
|
|
|
{
|
|
|
|
Clear();
|
|
|
|
}
|
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
bool S3fsMultiCurl::ClearEx(bool is_all)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
2013-09-14 21:50:39 +00:00
|
|
|
s3fscurlmap_t::iterator iter;
|
|
|
|
for(iter = cMap_req.begin(); iter != cMap_req.end(); cMap_req.erase(iter++)){
|
|
|
|
CURL* hCurl = (*iter).first;
|
|
|
|
S3fsCurl* s3fscurl = (*iter).second;
|
|
|
|
if(hMulti && hCurl){
|
|
|
|
curl_multi_remove_handle(hMulti, hCurl);
|
|
|
|
}
|
|
|
|
if(s3fscurl){
|
|
|
|
s3fscurl->DestroyCurlHandle();
|
|
|
|
delete s3fscurl; // with destroy curl handle.
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
if(hMulti){
|
|
|
|
curl_multi_cleanup(hMulti);
|
|
|
|
hMulti = NULL;
|
|
|
|
}
|
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
if(is_all){
|
|
|
|
for(iter = cMap_all.begin(); iter != cMap_all.end(); cMap_all.erase(iter++)){
|
|
|
|
S3fsCurl* s3fscurl = (*iter).second;
|
|
|
|
s3fscurl->DestroyCurlHandle();
|
|
|
|
delete s3fscurl;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
S3FS_MALLOCTRIM(0);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
S3fsMultiSuccessCallback S3fsMultiCurl::SetSuccessCallback(S3fsMultiSuccessCallback function)
|
|
|
|
{
|
|
|
|
S3fsMultiSuccessCallback old = SuccessCallback;
|
|
|
|
SuccessCallback = function;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
S3fsMultiRetryCallback S3fsMultiCurl::SetRetryCallback(S3fsMultiRetryCallback function)
|
|
|
|
{
|
|
|
|
S3fsMultiRetryCallback old = RetryCallback;
|
|
|
|
RetryCallback = function;
|
|
|
|
return old;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool S3fsMultiCurl::SetS3fsCurlObject(S3fsCurl* s3fscurl)
|
|
|
|
{
|
2013-09-14 21:50:39 +00:00
|
|
|
if(hMulti){
|
|
|
|
DPRN("Internal error: hMulti is not null");
|
|
|
|
return false;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(!s3fscurl){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
if(cMap_all.end() != cMap_all.find(s3fscurl->hCurl)){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
cMap_all[s3fscurl->hCurl] = s3fscurl;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S3fsMultiCurl::MultiPerform(void)
|
|
|
|
{
|
|
|
|
CURLMcode curlm_code;
|
|
|
|
int still_running;
|
|
|
|
|
|
|
|
if(!hMulti){
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send multi request.
|
|
|
|
do{
|
|
|
|
// Start making requests and check running.
|
|
|
|
still_running = 0;
|
|
|
|
do {
|
|
|
|
curlm_code = curl_multi_perform(hMulti, &still_running);
|
|
|
|
} while(curlm_code == CURLM_CALL_MULTI_PERFORM);
|
|
|
|
|
|
|
|
if(curlm_code != CURLM_OK) {
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("curl_multi_perform code: %d msg: %s", curlm_code, curl_multi_strerror(curlm_code));
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// Set timer when still running
|
|
|
|
if(still_running) {
|
|
|
|
long milliseconds;
|
|
|
|
fd_set r_fd;
|
|
|
|
fd_set w_fd;
|
|
|
|
fd_set e_fd;
|
|
|
|
FD_ZERO(&r_fd);
|
|
|
|
FD_ZERO(&w_fd);
|
|
|
|
FD_ZERO(&e_fd);
|
|
|
|
|
|
|
|
if(CURLM_OK != (curlm_code = curl_multi_timeout(hMulti, &milliseconds))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("curl_multi_timeout code: %d msg: %s", curlm_code, curl_multi_strerror(curlm_code));
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
|
|
|
if(milliseconds < 0){
|
|
|
|
milliseconds = 50;
|
|
|
|
}
|
|
|
|
if(milliseconds > 0) {
|
|
|
|
int max_fd;
|
|
|
|
struct timeval timeout;
|
|
|
|
timeout.tv_sec = 1000 * milliseconds / 1000000;
|
|
|
|
timeout.tv_usec = 1000 * milliseconds % 1000000;
|
|
|
|
|
|
|
|
if(CURLM_OK != (curlm_code = curl_multi_fdset(hMulti, &r_fd, &w_fd, &e_fd, &max_fd))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("curl_multi_fdset code: %d msg: %s", curlm_code, curl_multi_strerror(curlm_code));
|
2013-07-05 02:28:31 +00:00
|
|
|
return -EIO;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
if(-1 == select(max_fd + 1, &r_fd, &w_fd, &e_fd, &timeout)){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("failed select - errno(%d)", errno);
|
2013-07-05 02:28:31 +00:00
|
|
|
return -errno;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}while(still_running);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
int S3fsMultiCurl::MultiRead(void)
|
|
|
|
{
|
|
|
|
CURLMsg* msg;
|
|
|
|
int remaining_messages;
|
|
|
|
CURL* hCurl = NULL;
|
|
|
|
S3fsCurl* s3fscurl = NULL;
|
|
|
|
S3fsCurl* retrycurl= NULL;
|
|
|
|
|
|
|
|
while(NULL != (msg = curl_multi_info_read(hMulti, &remaining_messages))){
|
|
|
|
if(CURLMSG_DONE != msg->msg){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("curl_multi_info_read code: %d", msg->msg);
|
2013-07-05 02:28:31 +00:00
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
hCurl = msg->easy_handle;
|
2013-09-14 21:50:39 +00:00
|
|
|
if(cMap_req.end() != cMap_req.find(hCurl)){
|
|
|
|
s3fscurl = cMap_req[hCurl];
|
|
|
|
}else{
|
|
|
|
s3fscurl = NULL;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
retrycurl= NULL;
|
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
if(s3fscurl){
|
2013-11-11 13:45:35 +00:00
|
|
|
bool isRetry = false;
|
2013-09-14 21:50:39 +00:00
|
|
|
if(CURLE_OK == msg->data.result){
|
2013-09-26 05:00:21 +00:00
|
|
|
long responseCode = -1;
|
2013-11-11 13:45:35 +00:00
|
|
|
if(s3fscurl->GetResponseCode(responseCode)){
|
|
|
|
if(400 > responseCode){
|
|
|
|
// add into stat cache
|
|
|
|
if(SuccessCallback && !SuccessCallback(s3fscurl)){
|
2013-11-13 16:26:50 +00:00
|
|
|
DPRN("error from callback function(%s).", s3fscurl->url.c_str());
|
2013-11-11 13:45:35 +00:00
|
|
|
}
|
|
|
|
}else if(400 == responseCode){
|
|
|
|
// as possibly in multipart
|
2013-11-13 16:26:50 +00:00
|
|
|
DPRN("failed a request(%ld: %s)", responseCode, s3fscurl->url.c_str());
|
2013-11-11 13:45:35 +00:00
|
|
|
isRetry = true;
|
2013-11-19 01:48:53 +00:00
|
|
|
}else if(404 == responseCode){
|
|
|
|
// not found
|
|
|
|
DPRN("failed a request(%ld: %s)", responseCode, s3fscurl->url.c_str());
|
2013-11-18 02:29:41 +00:00
|
|
|
}else if(500 == responseCode){
|
2013-11-13 16:26:50 +00:00
|
|
|
// case of all other result, do retry.(11/13/2013)
|
|
|
|
// because it was found that s3fs got 500 error from S3, but could success
|
|
|
|
// to retry it.
|
|
|
|
DPRN("failed a request(%ld: %s)", responseCode, s3fscurl->url.c_str());
|
|
|
|
isRetry = true;
|
2013-11-18 02:29:41 +00:00
|
|
|
}else{
|
2013-11-19 01:48:53 +00:00
|
|
|
// Retry in other case.
|
2013-11-18 02:29:41 +00:00
|
|
|
DPRN("failed a request(%ld: %s)", responseCode, s3fscurl->url.c_str());
|
2013-11-19 01:48:53 +00:00
|
|
|
isRetry = true;
|
2013-09-14 21:50:39 +00:00
|
|
|
}
|
|
|
|
}else{
|
2013-11-13 16:26:50 +00:00
|
|
|
DPRN("failed a request(Unknown respons code: %s)", s3fscurl->url.c_str());
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2013-11-11 13:45:35 +00:00
|
|
|
}else{
|
2013-11-13 16:26:50 +00:00
|
|
|
DPRN("failed to read(remaining: %d code: %d msg: %s), so retry this.",
|
2013-11-11 13:45:35 +00:00
|
|
|
remaining_messages, msg->data.result, curl_easy_strerror(msg->data.result));
|
|
|
|
isRetry = true;
|
|
|
|
}
|
|
|
|
|
|
|
|
if(!isRetry){
|
2013-09-14 21:50:39 +00:00
|
|
|
cMap_req.erase(hCurl);
|
|
|
|
curl_multi_remove_handle(hMulti, hCurl);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
s3fscurl->DestroyCurlHandle();
|
|
|
|
delete s3fscurl;
|
|
|
|
|
|
|
|
}else{
|
|
|
|
cMap_req.erase(hCurl);
|
|
|
|
curl_multi_remove_handle(hMulti, hCurl);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
// For retry
|
|
|
|
if(RetryCallback){
|
|
|
|
retrycurl = RetryCallback(s3fscurl);
|
|
|
|
cMap_all[retrycurl->hCurl] = retrycurl;
|
|
|
|
}
|
|
|
|
if(s3fscurl != retrycurl){
|
|
|
|
s3fscurl->DestroyCurlHandle();
|
|
|
|
delete s3fscurl;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}else{
|
|
|
|
assert(false);
|
2013-07-05 02:28:31 +00:00
|
|
|
}
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-03-30 13:37:14 +00:00
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
int S3fsMultiCurl::Request(void)
|
|
|
|
{
|
|
|
|
int result;
|
|
|
|
CURLMcode curlm_code;
|
|
|
|
|
2013-08-19 06:29:24 +00:00
|
|
|
FPRNNN("[count=%zu]", cMap_all.size());
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
if(hMulti){
|
2013-09-14 21:50:39 +00:00
|
|
|
DPRNNN("Warning: hMulti is not null, thus clear itself.");
|
|
|
|
ClearEx(false);
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// Make request list.
|
|
|
|
//
|
|
|
|
// Send multi request loop( with retry )
|
|
|
|
// (When many request is sends, sometimes gets "Couldn't connect to server")
|
|
|
|
//
|
|
|
|
while(0 < cMap_all.size()){
|
|
|
|
// populate the multi interface with an initial set of requests
|
|
|
|
if(NULL == (hMulti = curl_multi_init())){
|
|
|
|
Clear();
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set curl handle to multi handle
|
|
|
|
int cnt;
|
|
|
|
s3fscurlmap_t::iterator iter;
|
|
|
|
for(cnt = 0, iter = cMap_all.begin(); cnt < S3fsMultiCurl::max_multireq && iter != cMap_all.end(); cMap_all.erase(iter++), cnt++){
|
|
|
|
CURL* hCurl = (*iter).first;
|
|
|
|
S3fsCurl* s3fscurl = (*iter).second;
|
|
|
|
|
|
|
|
if(CURLM_OK != (curlm_code = curl_multi_add_handle(hMulti, hCurl))){
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRN("curl_multi_add_handle code: %d msg: %s", curlm_code, curl_multi_strerror(curlm_code));
|
2013-07-05 02:28:31 +00:00
|
|
|
Clear();
|
|
|
|
return -EIO;
|
|
|
|
}
|
|
|
|
cMap_req[hCurl] = s3fscurl;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Send multi request.
|
|
|
|
if(0 != (result = MultiPerform())){
|
|
|
|
Clear();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read the result
|
|
|
|
if(0 != (result = MultiRead())){
|
|
|
|
Clear();
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
// Cleanup curl handle in multi handle
|
|
|
|
ClearEx(false);
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
return 0;
|
|
|
|
}
|
2013-03-30 13:37:14 +00:00
|
|
|
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Class AdditionalHeader
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
AdditionalHeader AdditionalHeader::singleton;
|
|
|
|
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Class AdditionalHeader method
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
AdditionalHeader::AdditionalHeader()
|
|
|
|
{
|
|
|
|
if(this == AdditionalHeader::get()){
|
|
|
|
is_enable = false;
|
|
|
|
}else{
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
AdditionalHeader::~AdditionalHeader()
|
|
|
|
{
|
|
|
|
if(this == AdditionalHeader::get()){
|
|
|
|
Unload();
|
|
|
|
}else{
|
|
|
|
assert(false);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AdditionalHeader::Load(const char* file)
|
|
|
|
{
|
|
|
|
if(!file){
|
|
|
|
DPRNNN("file is NULL.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
Unload();
|
|
|
|
|
|
|
|
ifstream AH(file);
|
|
|
|
if(!AH.good()){
|
|
|
|
DPRNNN("Could not open file(%s).", file);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// read file
|
|
|
|
string line;
|
|
|
|
while(getline(AH, line)){
|
|
|
|
if('#' == line[0]){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
if(0 == line.size()){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// load a line
|
|
|
|
stringstream ss(line);
|
|
|
|
string key(""); // suffix(key)
|
|
|
|
string head; // additional HTTP header
|
|
|
|
string value; // header value
|
|
|
|
if(0 == isblank(line[0])){
|
|
|
|
ss >> key;
|
|
|
|
}
|
|
|
|
if(ss){
|
|
|
|
ss >> head;
|
|
|
|
if(ss && static_cast<size_t>(ss.tellg()) < line.size()){
|
|
|
|
value = line.substr(static_cast<int>(ss.tellg()) + 1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// check it
|
|
|
|
if(0 == head.size()){
|
|
|
|
if(0 == key.size()){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
DPRNNN("file format error: %s key(suffix) is no HTTP header value.", key.c_str());
|
|
|
|
Unload();
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
// set charcntlist
|
|
|
|
int keylen = key.size();
|
|
|
|
charcnt_list_t::iterator iter;
|
|
|
|
for(iter = charcntlist.begin(); iter != charcntlist.end(); ++iter){
|
|
|
|
if(keylen == (*iter)){
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if(iter == charcntlist.end()){
|
|
|
|
charcntlist.push_back(keylen);
|
|
|
|
}
|
|
|
|
// set addheader
|
|
|
|
if(addheader.end() == addheader.find(key)){
|
|
|
|
headerpair_t hpair;
|
|
|
|
hpair[head] = value;
|
|
|
|
addheader[key] = hpair;
|
|
|
|
}else{
|
|
|
|
(addheader[key])[head] = value;
|
|
|
|
}
|
|
|
|
// set flag
|
|
|
|
if(!is_enable){
|
|
|
|
is_enable = true;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
void AdditionalHeader::Unload(void)
|
|
|
|
{
|
|
|
|
is_enable = false;
|
|
|
|
charcntlist.clear();
|
|
|
|
addheader.clear();
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AdditionalHeader::AddHeader(headers_t& meta, const char* path) const
|
|
|
|
{
|
|
|
|
if(!is_enable){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
if(!path){
|
|
|
|
DPRNNN("path is NULL.");
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
int nPathLen = strlen(path);
|
|
|
|
for(charcnt_list_t::const_iterator iter = charcntlist.begin(); iter != charcntlist.end(); ++iter){
|
|
|
|
// get target charactor count
|
|
|
|
if(nPathLen < (*iter)){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
// make target suffix(same charactor count) & find
|
|
|
|
string suffix(&path[nPathLen - (*iter)]);
|
|
|
|
if(addheader.end() == addheader.find(suffix)){
|
|
|
|
continue;
|
|
|
|
}
|
|
|
|
for(headerpair_t::const_iterator piter = addheader.at(suffix).begin(); piter != addheader.at(suffix).end(); ++piter){
|
|
|
|
// Adding header
|
|
|
|
meta[(*piter).first] = (*piter).second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
struct curl_slist* AdditionalHeader::AddHeader(struct curl_slist* list, const char* path) const
|
|
|
|
{
|
|
|
|
headers_t meta;
|
|
|
|
|
|
|
|
if(!AddHeader(meta, path)){
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
|
|
|
|
string slistval = (*iter).first + ": " + (*iter).second;
|
|
|
|
// Adding header
|
|
|
|
list = curl_slist_sort_insert(list, slistval.c_str());
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
meta.clear();
|
|
|
|
S3FS_MALLOCTRIM(0);
|
Fixed Issue 229 and Changes codes
1) Set metadata "Content-Encoding" automatically(Issue 292)
For this issue, s3fs is added new option "ahbe_conf".
New option means the configuration file path, and this file specifies
additional HTTP header by file(object) extension.
Thus you can specify any HTTP header for each object by extension.
* ahbe_conf file format:
-----------
line = [file suffix] HTTP-header [HTTP-header-values]
file suffix = file(object) suffix, if this field is empty,
it means "*"(all object).
HTTP-header = additional HTTP header name
HTTP-header-values = additional HTTP header value
-----------
* Example:
-----------
.gz Content-Encoding gzip
.Z Content-Encoding compress
X-S3FS-MYHTTPHEAD myvalue
-----------
A sample configuration file is uploaded in "test" directory.
If ahbe_conf parameter is specified, s3fs loads it's configuration
and compares extension(suffix) of object(file) when uploading
(PUT/POST) it. If the extension is same, s3fs adds/sends specified
HTTP header and value.
A case of sample configuration file, if a object(it's extension is
".gz") which already has Content-Encoding HTTP header is renamed
to ".txt" extension, s3fs does not set Content-Encoding. Because
".txt" is not match any line in configuration file.
So, s3fs matches the extension by each PUT/POST action.
* Please take care about "Content-Encoding".
This new option allows setting ANY HTTP header by object extension.
For example, you can specify "Content-Encoding" for ".gz"/etc
extension in configuration. But this means that S3 always returns
"Content-Encoding: gzip" when a client requests with other
"Accept-Encoding:" header. It SHOULD NOT be good.
Please see RFC 2616.
2) Changes about allow_other/uid/gid option for mount point
I reviewed about mount point permission and allow_other/uid/gid
options, and found bugs about these.
s3fs is fixed bugs and changed to the following specifications.
* s3fs only allows uid(gid) options as 0(root), when the effective
user is zero(root).
* A mount point(directory) must have a permission to allow
accessing by effective user/group.
* If allow_other option is specified, the mount point permission
is set 0777(all users allow all access).
In another case, the mount point is set 0700(only allows
effective user).
* When uid/gid option is specified, the mount point owner/group
is set uid/gid option value.
If uid/gid is not set, it is set effective user/group id.
This changes maybe fixes some issue(321, 338).
3) Changes a logic about (Issue 229)
The chmod command returns -EIO when changing the mount point.
It is correct, s3fs can not changed owner/group/mtime for the
mount point, but s3fs sends a request for changing the bucket.
This revision does not send the request, and returns EIO as
soon as possible.
git-svn-id: http://s3fs.googlecode.com/svn/trunk@465 df820570-a93a-0410-bd06-b72b767a4274
2013-08-16 19:24:01 +00:00
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
bool AdditionalHeader::Dump(void) const
|
|
|
|
{
|
|
|
|
if(!foreground2){
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
// charactor count list
|
|
|
|
stringstream ssdbg;
|
|
|
|
ssdbg << "Charactor count list[" << charcntlist.size() << "] = {";
|
|
|
|
for(charcnt_list_t::const_iterator citer = charcntlist.begin(); citer != charcntlist.end(); ++citer){
|
|
|
|
ssdbg << " " << (*citer);
|
|
|
|
}
|
|
|
|
ssdbg << " }\n";
|
|
|
|
|
|
|
|
// additional header
|
|
|
|
ssdbg << "Additional Header list[" << addheader.size() << "] = {\n";
|
|
|
|
for(addheader_t::const_iterator aiter = addheader.begin(); aiter != addheader.end(); ++aiter){
|
|
|
|
string key = (*aiter).first;
|
|
|
|
if(0 == key.size()){
|
|
|
|
key = "*";
|
|
|
|
}
|
|
|
|
for(headerpair_t::const_iterator piter = (*aiter).second.begin(); piter != (*aiter).second.end(); ++piter){
|
|
|
|
ssdbg << " " << key << "\t--->\t" << (*piter).first << ": " << (*piter).second << "\n";
|
|
|
|
}
|
|
|
|
}
|
|
|
|
ssdbg << "}";
|
|
|
|
|
|
|
|
// print all
|
|
|
|
FPRNINFO("%s", ssdbg.str().c_str());
|
|
|
|
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
//-------------------------------------------------------------------
|
|
|
|
// Utility functions
|
|
|
|
//-------------------------------------------------------------------
|
|
|
|
string GetContentMD5(int fd)
|
|
|
|
{
|
|
|
|
BIO* b64;
|
|
|
|
BIO* bmem;
|
|
|
|
BUF_MEM* bptr;
|
|
|
|
string Signature;
|
|
|
|
unsigned char* md5hex;
|
|
|
|
|
2013-08-19 06:29:24 +00:00
|
|
|
if(NULL == (md5hex = md5hexsum(fd, 0, -1))){
|
2013-07-05 02:28:31 +00:00
|
|
|
return string("");
|
|
|
|
}
|
|
|
|
|
|
|
|
b64 = BIO_new(BIO_f_base64());
|
|
|
|
bmem = BIO_new(BIO_s_mem());
|
|
|
|
b64 = BIO_push(b64, bmem);
|
|
|
|
|
|
|
|
BIO_write(b64, md5hex, MD5_DIGEST_LENGTH);
|
|
|
|
free(md5hex);
|
|
|
|
if(1 != BIO_flush(b64)){
|
2013-09-14 21:50:39 +00:00
|
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
2013-07-05 02:28:31 +00:00
|
|
|
BIO_free_all(b64);
|
|
|
|
return string("");
|
|
|
|
}
|
|
|
|
BIO_get_mem_ptr(b64, &bptr);
|
2013-09-14 21:50:39 +00:00
|
|
|
Signature.assign(bptr->data, bptr->length - 1);
|
2013-07-05 02:28:31 +00:00
|
|
|
|
2013-09-14 21:50:39 +00:00
|
|
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
2013-07-05 02:28:31 +00:00
|
|
|
BIO_free_all(b64);
|
|
|
|
|
|
|
|
return Signature;
|
|
|
|
}
|
|
|
|
|
2013-08-21 08:39:06 +00:00
|
|
|
unsigned char* md5hexsum(int fd, off_t start, ssize_t size)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
|
|
|
MD5_CTX c;
|
|
|
|
char buf[512];
|
|
|
|
ssize_t bytes;
|
2013-09-14 21:50:39 +00:00
|
|
|
unsigned char* result;
|
2013-07-05 02:28:31 +00:00
|
|
|
|
2014-03-03 16:19:08 +00:00
|
|
|
if(-1 == size){
|
|
|
|
struct stat st;
|
|
|
|
if(-1 == fstat(fd, &st)){
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
size = static_cast<ssize_t>(st.st_size);
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
// seek to top of file.
|
2013-07-12 00:33:36 +00:00
|
|
|
if(-1 == lseek(fd, start, SEEK_SET)){
|
2013-07-05 02:28:31 +00:00
|
|
|
return NULL;
|
|
|
|
}
|
2013-09-14 21:50:39 +00:00
|
|
|
if(NULL == (result = (unsigned char*)malloc(MD5_DIGEST_LENGTH))){
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
|
|
|
|
memset(buf, 0, 512);
|
|
|
|
MD5_Init(&c);
|
2013-07-12 00:33:36 +00:00
|
|
|
for(ssize_t total = 0; total < size; total += bytes){
|
|
|
|
bytes = 512 < (size - total) ? 512 : (size - total);
|
|
|
|
bytes = read(fd, buf, bytes);
|
|
|
|
if(0 == bytes){
|
|
|
|
// end of file
|
|
|
|
break;
|
|
|
|
}else if(-1 == bytes){
|
|
|
|
// error
|
2013-08-10 15:29:39 +00:00
|
|
|
DPRNNN("file read error(%d)", errno);
|
2013-07-12 00:33:36 +00:00
|
|
|
free(result);
|
|
|
|
return NULL;
|
|
|
|
}
|
2013-07-05 02:28:31 +00:00
|
|
|
MD5_Update(&c, buf, bytes);
|
|
|
|
memset(buf, 0, 512);
|
|
|
|
}
|
|
|
|
MD5_Final(result, &c);
|
|
|
|
|
2013-07-12 00:33:36 +00:00
|
|
|
if(-1 == lseek(fd, start, SEEK_SET)){
|
2013-07-05 02:28:31 +00:00
|
|
|
free(result);
|
|
|
|
return NULL;
|
2013-03-30 13:37:14 +00:00
|
|
|
}
|
|
|
|
return result;
|
|
|
|
}
|
|
|
|
|
2013-08-21 08:39:06 +00:00
|
|
|
string md5sum(int fd, off_t start, ssize_t size)
|
2013-07-05 02:28:31 +00:00
|
|
|
{
|
|
|
|
char md5[2 * MD5_DIGEST_LENGTH + 1];
|
|
|
|
char hexbuf[3];
|
|
|
|
unsigned char* md5hex;
|
|
|
|
|
2013-07-12 00:33:36 +00:00
|
|
|
if(NULL == (md5hex = md5hexsum(fd, start, size))){
|
2013-07-05 02:28:31 +00:00
|
|
|
return string("");
|
|
|
|
}
|
|
|
|
|
|
|
|
memset(md5, 0, 2 * MD5_DIGEST_LENGTH + 1);
|
|
|
|
for(int i = 0; i < MD5_DIGEST_LENGTH; i++) {
|
|
|
|
snprintf(hexbuf, 3, "%02x", md5hex[i]);
|
|
|
|
strncat(md5, hexbuf, 2);
|
|
|
|
}
|
|
|
|
free(md5hex);
|
|
|
|
|
|
|
|
return string(md5);
|
|
|
|
}
|
|
|
|
|
|
|
|
//
|
|
|
|
// curl_slist_sort_insert
|
|
|
|
// This function is like curl_slist_append function, but this adds data by a-sorting.
|
|
|
|
// Because AWS signature needs sorted header.
|
|
|
|
//
|
|
|
|
struct curl_slist* curl_slist_sort_insert(struct curl_slist* list, const char* data)
|
|
|
|
{
|
|
|
|
struct curl_slist* curpos;
|
|
|
|
struct curl_slist* lastpos;
|
|
|
|
struct curl_slist* new_item;
|
|
|
|
|
|
|
|
if(!data){
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
if(NULL == (new_item = (struct curl_slist*)malloc(sizeof(struct curl_slist)))){
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
if(NULL == (new_item->data = strdup(data))){
|
|
|
|
free(new_item);
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
new_item->next = NULL;
|
|
|
|
|
2013-11-11 13:45:35 +00:00
|
|
|
string strnew = data;
|
|
|
|
string::size_type pos = strnew.find(':', 0);
|
|
|
|
if(string::npos != pos){
|
|
|
|
strnew = strnew.substr(0, pos);
|
|
|
|
}
|
|
|
|
|
2013-07-05 02:28:31 +00:00
|
|
|
for(lastpos = NULL, curpos = list; curpos; curpos = curpos->next){
|
2013-11-11 13:45:35 +00:00
|
|
|
string strcur = curpos->data;
|
|
|
|
if(string::npos != (pos = strcur.find(':', 0))){
|
|
|
|
strcur = strcur.substr(0, pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
int result = strcmp(strnew.c_str(), strcur.c_str());
|
2013-07-05 02:28:31 +00:00
|
|
|
if(0 == result){
|
|
|
|
// same data, so replace it.
|
|
|
|
if(lastpos){
|
|
|
|
lastpos->next = new_item;
|
|
|
|
}else{
|
|
|
|
list = new_item;
|
|
|
|
}
|
|
|
|
new_item->next = curpos->next;
|
2013-07-05 05:41:46 +00:00
|
|
|
free(curpos->data);
|
2013-07-05 02:28:31 +00:00
|
|
|
free(curpos);
|
|
|
|
break;
|
|
|
|
|
|
|
|
}else if(0 > result){
|
|
|
|
// add data before curpos.
|
|
|
|
if(lastpos){
|
|
|
|
lastpos->next = new_item;
|
|
|
|
}else{
|
|
|
|
list = new_item;
|
|
|
|
}
|
|
|
|
new_item->next = curpos;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
lastpos = curpos;
|
|
|
|
}
|
|
|
|
if(!curpos){
|
|
|
|
// append to last pos
|
|
|
|
if(lastpos){
|
|
|
|
lastpos->next = new_item;
|
|
|
|
}else{
|
|
|
|
// a case of list is null
|
|
|
|
list = new_item;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return list;
|
|
|
|
}
|
|
|
|
|
|
|
|
// function for using global values
|
|
|
|
bool MakeUrlResource(const char* realpath, string& resourcepath, string& url)
|
|
|
|
{
|
|
|
|
if(!realpath){
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
resourcepath = urlEncode(service_path + bucket + realpath);
|
|
|
|
url = host + resourcepath;
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/// END
|