mirror of
https://github.com/s3fs-fuse/s3fs-fuse.git
synced 2025-01-22 21:38:24 +00:00
Changes codes
1) Changed codes about memory leak For memory leak, below codes are changed. * calls malloc_trim function * calls initializing NSS function, and adds configure option "--enable-nss-init". If libcurl is with NSS, s3fs initializes NSS manually. This initializing NSS is enabled by "--enable-nss-init" option at configure. if this option is specified, you need "nss-devel" package. * calls initializing libxml2(xmlInitParser). * BIO functions have memory leak, calls CRYPTO_free_ex_data. * changes cache structure. * changes cache out logic to LRU. * sets alignment for allcated memory in body data structure. * adds ssl session into share handle. and adds nosscache option. * deletes unused allocated memory.(bug) * changes defaule parallel count of head request in readdir (500->20) * fixes some bugs. git-svn-id: http://s3fs.googlecode.com/svn/trunk@482 df820570-a93a-0410-bd06-b72b767a4274
This commit is contained in:
parent
d45f4707ea
commit
42b74c9d2e
91
configure.ac
91
configure.ac
@ -1,9 +1,27 @@
|
|||||||
|
######################################################################
|
||||||
|
# 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.
|
||||||
|
######################################################################
|
||||||
dnl Process this file with autoconf to produce a configure script.
|
dnl Process this file with autoconf to produce a configure script.
|
||||||
|
|
||||||
AC_PREREQ(2.59)
|
AC_PREREQ(2.59)
|
||||||
AC_INIT(s3fs, 1.73)
|
AC_INIT(s3fs, 1.73)
|
||||||
|
|
||||||
|
|
||||||
AC_CANONICAL_SYSTEM
|
AC_CANONICAL_SYSTEM
|
||||||
AM_INIT_AUTOMAKE()
|
AM_INIT_AUTOMAKE()
|
||||||
|
|
||||||
@ -13,6 +31,77 @@ CXXFLAGS="$CXXFLAGS -Wall -D_FILE_OFFSET_BITS=64"
|
|||||||
|
|
||||||
PKG_CHECK_MODULES([DEPS], [fuse >= 2.8.4 libcurl >= 7.0 libxml-2.0 >= 2.6 libcrypto >= 0.9])
|
PKG_CHECK_MODULES([DEPS], [fuse >= 2.8.4 libcurl >= 7.0 libxml-2.0 >= 2.6 libcrypto >= 0.9])
|
||||||
|
|
||||||
|
dnl malloc_trim function
|
||||||
|
AC_CHECK_FUNCS(malloc_trim, , )
|
||||||
|
|
||||||
|
dnl Initializing NSS(temporally)
|
||||||
|
AC_MSG_CHECKING([Initializing libcurl build with NSS])
|
||||||
|
AC_ARG_ENABLE(
|
||||||
|
nss-init,
|
||||||
|
[
|
||||||
|
AS_HELP_STRING(
|
||||||
|
[--enable-nss-init],
|
||||||
|
[Inilializing libcurl with NSS (default is no)]
|
||||||
|
)
|
||||||
|
],
|
||||||
|
[
|
||||||
|
case "${enableval}" in
|
||||||
|
yes)
|
||||||
|
AC_MSG_RESULT(yes)
|
||||||
|
nss_init_enabled=yes
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
nss_init_enabled=no
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
],
|
||||||
|
[
|
||||||
|
AC_MSG_RESULT(no)
|
||||||
|
nss_init_enabled=no
|
||||||
|
])
|
||||||
|
|
||||||
|
AS_IF(
|
||||||
|
[test $nss_init_enabled = yes],
|
||||||
|
[
|
||||||
|
AC_DEFINE(NSS_INIT_ENABLED, 1)
|
||||||
|
AC_CHECK_LIB(nss3, NSS_NoDB_Init, , [AC_MSG_ERROR(not found NSS libraries)])
|
||||||
|
AC_CHECK_LIB(plds4, PL_ArenaFinish, , [AC_MSG_ERROR(not found PL_ArenaFinish)])
|
||||||
|
AC_CHECK_LIB(nspr4, PR_Cleanup, , [AC_MSG_ERROR(not found PR_Cleanup)])
|
||||||
|
AC_CHECK_HEADER(nss.h, , [AC_MSG_ERROR(not found nss.h)])
|
||||||
|
AC_CHECK_HEADER(nspr4/prinit.h, , [AC_MSG_ERROR(not found prinit.h)])
|
||||||
|
AC_PATH_PROG(NSSCONFIG, [nss-config], no)
|
||||||
|
AS_IF(
|
||||||
|
[test $NSSCONFIG = no],
|
||||||
|
[
|
||||||
|
DEPS_CFLAGS="$DEPS_CFLAGS -I/usr/include/nss3"
|
||||||
|
DEPS_LIBS="$DEPS_LIBS -lnss3"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
addcflags=`nss-config --cflags`
|
||||||
|
DEPS_CFLAGS="$DEPS_CFLAGS $addcflags"
|
||||||
|
dnl addlib=`nss-config --libs`
|
||||||
|
dnl DEPS_LIBS="$DEPS_LIBS $addlib"
|
||||||
|
DEPS_LIBS="$DEPS_LIBS -lnss3"
|
||||||
|
])
|
||||||
|
AC_PATH_PROG(NSPRCONFIG, [nspr-config], no)
|
||||||
|
AS_IF(
|
||||||
|
[test $NSPRCONFIG = no],
|
||||||
|
[
|
||||||
|
DEPS_CFLAGS="$DEPS_CFLAGS -I/usr/include/nspr4"
|
||||||
|
DEPS_LIBS="$DEPS_LIBS -lnspr4 -lplds4"
|
||||||
|
],
|
||||||
|
[
|
||||||
|
addcflags=`nspr-config --cflags`
|
||||||
|
DEPS_CFLAGS="$DEPS_CFLAGS $addcflags"
|
||||||
|
dnl addlib=`nspr-config --libs`
|
||||||
|
dnl DEPS_LIBS="$DEPS_LIBS $addlib"
|
||||||
|
DEPS_LIBS="$DEPS_LIBS -lnspr4 -lplds4"
|
||||||
|
])
|
||||||
|
])
|
||||||
|
|
||||||
|
AS_UNSET(nss_enabled)
|
||||||
|
|
||||||
AC_CONFIG_FILES(Makefile src/Makefile test/Makefile doc/Makefile)
|
AC_CONFIG_FILES(Makefile src/Makefile test/Makefile doc/Makefile)
|
||||||
AC_OUTPUT
|
AC_OUTPUT
|
||||||
|
|
||||||
|
@ -117,7 +117,10 @@ You can specify this option for performance, s3fs memorizes in stat cache that t
|
|||||||
\fB\-o\fR nodnscache - disable dns cache.
|
\fB\-o\fR nodnscache - disable dns cache.
|
||||||
s3fs is always using dns cache, this option make dns cache disable.
|
s3fs is always using dns cache, this option make dns cache disable.
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR multireq_max (default="500")
|
\fB\-o\fR nosscache - disable ssl session cache.
|
||||||
|
s3fs is always using ssl session cache, this option make ssl session cache disable.
|
||||||
|
.TP
|
||||||
|
\fB\-o\fR multireq_max (default="20")
|
||||||
maximum number of parallel request for listing objects.
|
maximum number of parallel request for listing objects.
|
||||||
.TP
|
.TP
|
||||||
\fB\-o\fR parallel_count (default="5")
|
\fB\-o\fR parallel_count (default="5")
|
||||||
|
174
src/cache.cpp
174
src/cache.cpp
@ -33,6 +33,7 @@
|
|||||||
#include <list>
|
#include <list>
|
||||||
|
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
|
#include "s3fs.h"
|
||||||
#include "s3fs_util.h"
|
#include "s3fs_util.h"
|
||||||
|
|
||||||
using namespace std;
|
using namespace std;
|
||||||
@ -46,22 +47,20 @@ pthread_mutex_t StatCache::stat_cache_lock;
|
|||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
// Constructor/Destructor
|
// Constructor/Destructor
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
StatCache::StatCache()
|
StatCache::StatCache() : IsExpireTime(false), ExpireTime(0), CacheSize(1000), IsCacheNoObject(false)
|
||||||
{
|
{
|
||||||
if(this == StatCache::getStatCacheData()){
|
if(this == StatCache::getStatCacheData()){
|
||||||
|
stat_cache.clear();
|
||||||
pthread_mutex_init(&(StatCache::stat_cache_lock), NULL);
|
pthread_mutex_init(&(StatCache::stat_cache_lock), NULL);
|
||||||
}else{
|
}else{
|
||||||
assert(false);
|
assert(false);
|
||||||
}
|
}
|
||||||
CacheSize = 1000;
|
|
||||||
ExpireTime = 0;
|
|
||||||
IsExpireTime = false;
|
|
||||||
IsCacheNoObject = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
StatCache::~StatCache()
|
StatCache::~StatCache()
|
||||||
{
|
{
|
||||||
if(this == StatCache::getStatCacheData()){
|
if(this == StatCache::getStatCacheData()){
|
||||||
|
Clear();
|
||||||
pthread_mutex_destroy(&(StatCache::stat_cache_lock));
|
pthread_mutex_destroy(&(StatCache::stat_cache_lock));
|
||||||
}else{
|
}else{
|
||||||
assert(false);
|
assert(false);
|
||||||
@ -111,6 +110,20 @@ bool StatCache::SetCacheNoObject(bool flag)
|
|||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void StatCache::Clear(void)
|
||||||
|
{
|
||||||
|
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||||
|
|
||||||
|
for(stat_cache_t::iterator iter = stat_cache.begin(); iter != stat_cache.end(); stat_cache.erase(iter++)){
|
||||||
|
if((*iter).second){
|
||||||
|
delete (*iter).second;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
|
}
|
||||||
|
|
||||||
bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce)
|
bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce)
|
||||||
{
|
{
|
||||||
bool is_delete_cache = false;
|
bool is_delete_cache = false;
|
||||||
@ -128,9 +141,10 @@ bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool ove
|
|||||||
iter = stat_cache.find(strpath.c_str());
|
iter = stat_cache.find(strpath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(iter != stat_cache.end()) {
|
if(iter != stat_cache.end() && (*iter).second){
|
||||||
if(!IsExpireTime|| ((*iter).second.cache_date + ExpireTime) >= time(NULL)){
|
stat_cache_entry* ent = (*iter).second;
|
||||||
if((*iter).second.noobjcache){
|
if(!IsExpireTime|| (ent->cache_date + ExpireTime) >= time(NULL)){
|
||||||
|
if(ent->noobjcache){
|
||||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
if(!IsCacheNoObject){
|
if(!IsCacheNoObject){
|
||||||
// need to delete this cache.
|
// need to delete this cache.
|
||||||
@ -142,7 +156,7 @@ bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool ove
|
|||||||
}
|
}
|
||||||
// hit without checking etag
|
// hit without checking etag
|
||||||
if(petag){
|
if(petag){
|
||||||
string stretag = (*iter).second.meta["ETag"];
|
string stretag = ent->meta["ETag"];
|
||||||
if('\0' != petag[0] && 0 != strcmp(petag, stretag.c_str())){
|
if('\0' != petag[0] && 0 != strcmp(petag, stretag.c_str())){
|
||||||
is_delete_cache = true;
|
is_delete_cache = true;
|
||||||
}
|
}
|
||||||
@ -150,24 +164,22 @@ bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool ove
|
|||||||
if(is_delete_cache){
|
if(is_delete_cache){
|
||||||
// not hit by different ETag
|
// not hit by different ETag
|
||||||
DPRNNN("stat cache not hit by ETag[path=%s][time=%jd][hit count=%lu][ETag(%s)!=(%s)]",
|
DPRNNN("stat cache not hit by ETag[path=%s][time=%jd][hit count=%lu][ETag(%s)!=(%s)]",
|
||||||
strpath.c_str(), (intmax_t)((*iter).second.cache_date), (*iter).second.hit_count,
|
strpath.c_str(), (intmax_t)(ent->cache_date), ent->hit_count, petag ? petag : "null", ent->meta["ETag"].c_str());
|
||||||
petag ? petag : "null", (*iter).second.meta["ETag"].c_str());
|
|
||||||
}else{
|
}else{
|
||||||
// hit
|
// hit
|
||||||
DPRNNN("stat cache hit [path=%s][time=%jd][hit count=%lu]",
|
DPRNNN("stat cache hit [path=%s][time=%jd][hit count=%lu]", strpath.c_str(), (intmax_t)(ent->cache_date), ent->hit_count);
|
||||||
strpath.c_str(), (intmax_t)((*iter).second.cache_date), (*iter).second.hit_count);
|
|
||||||
|
|
||||||
if(pst!= NULL){
|
if(pst!= NULL){
|
||||||
*pst= (*iter).second.stbuf;
|
*pst= ent->stbuf;
|
||||||
}
|
}
|
||||||
if(meta != NULL){
|
if(meta != NULL){
|
||||||
meta->clear();
|
*meta = ent->meta;
|
||||||
(*meta) = (*iter).second.meta;
|
|
||||||
}
|
}
|
||||||
if(pisforce != NULL){
|
if(pisforce != NULL){
|
||||||
(*pisforce) = (*iter).second.isforce;
|
(*pisforce) = ent->isforce;
|
||||||
}
|
}
|
||||||
(*iter).second.hit_count++;
|
ent->hit_count++;
|
||||||
|
ent->cache_date = time(NULL);
|
||||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -206,10 +218,11 @@ bool StatCache::IsNoObjectCache(string& key, bool overcheck)
|
|||||||
iter = stat_cache.find(strpath.c_str());
|
iter = stat_cache.find(strpath.c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
if(iter != stat_cache.end()) {
|
if(iter != stat_cache.end() && (*iter).second) {
|
||||||
if(!IsExpireTime|| ((*iter).second.cache_date + ExpireTime) >= time(NULL)){
|
if(!IsExpireTime|| ((*iter).second->cache_date + ExpireTime) >= time(NULL)){
|
||||||
if((*iter).second.noobjcache){
|
if((*iter).second->noobjcache){
|
||||||
// noobjcache = true means no object.
|
// noobjcache = true means no object.
|
||||||
|
(*iter).second->cache_date = time(NULL);
|
||||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -233,46 +246,52 @@ bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir)
|
|||||||
}
|
}
|
||||||
DPRNNN("add stat cache entry[path=%s]", key.c_str());
|
DPRNNN("add stat cache entry[path=%s]", key.c_str());
|
||||||
|
|
||||||
|
if(stat_cache.end() != stat_cache.find(key)){
|
||||||
|
DelStat(key.c_str());
|
||||||
|
}else{
|
||||||
if(stat_cache.size() > CacheSize){
|
if(stat_cache.size() > CacheSize){
|
||||||
if(!TruncateCache()){
|
if(!TruncateCache()){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
struct stat st;
|
|
||||||
if(!convert_header_to_stat(key.c_str(), meta, &st, forcedir)){
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
// make new
|
||||||
stat_cache[key].stbuf = st;
|
stat_cache_entry* ent = new stat_cache_entry();
|
||||||
stat_cache[key].hit_count = 0;
|
if(!convert_header_to_stat(key.c_str(), meta, &(ent->stbuf), forcedir)){
|
||||||
stat_cache[key].cache_date = time(NULL); // Set time.
|
delete ent;
|
||||||
stat_cache[key].isforce = forcedir;
|
return false;
|
||||||
stat_cache[key].noobjcache = false;
|
}
|
||||||
|
ent->hit_count = 0;
|
||||||
|
ent->cache_date = time(NULL); // Set time.
|
||||||
|
ent->isforce = forcedir;
|
||||||
|
ent->noobjcache = false;
|
||||||
|
ent->meta.clear();
|
||||||
//copy only some keys
|
//copy only some keys
|
||||||
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
|
for(headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter){
|
||||||
string tag = (*iter).first;
|
string tag = (*iter).first;
|
||||||
string value = (*iter).second;
|
string value = (*iter).second;
|
||||||
if(tag == "Content-Type"){
|
if(tag == "Content-Type"){
|
||||||
stat_cache[key].meta[tag] = value;
|
ent->meta[tag] = value;
|
||||||
}else if(tag == "Content-Length"){
|
}else if(tag == "Content-Length"){
|
||||||
stat_cache[key].meta[tag] = value;
|
ent->meta[tag] = value;
|
||||||
}else if(tag == "ETag"){
|
}else if(tag == "ETag"){
|
||||||
stat_cache[key].meta[tag] = value;
|
ent->meta[tag] = value;
|
||||||
}else if(tag == "Last-Modified"){
|
}else if(tag == "Last-Modified"){
|
||||||
stat_cache[key].meta[tag] = value;
|
ent->meta[tag] = value;
|
||||||
}else if(tag.substr(0, 5) == "x-amz"){
|
}else if(tag.substr(0, 5) == "x-amz"){
|
||||||
stat_cache[key].meta[tag] = value;
|
ent->meta[tag] = value;
|
||||||
}else{
|
}else{
|
||||||
// Check for upper case
|
// Check for upper case
|
||||||
transform(tag.begin(), tag.end(), tag.begin(), static_cast<int (*)(int)>(std::tolower));
|
transform(tag.begin(), tag.end(), tag.begin(), static_cast<int (*)(int)>(std::tolower));
|
||||||
if(tag.substr(0, 5) == "x-amz"){
|
if(tag.substr(0, 5) == "x-amz"){
|
||||||
stat_cache[key].meta[tag] = value;
|
ent->meta[tag] = value;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// add
|
||||||
|
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||||
|
stat_cache[key] = ent;
|
||||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -288,21 +307,27 @@ bool StatCache::AddNoObjectCache(string& key)
|
|||||||
}
|
}
|
||||||
DPRNNN("add no object cache entry[path=%s]", key.c_str());
|
DPRNNN("add no object cache entry[path=%s]", key.c_str());
|
||||||
|
|
||||||
|
if(stat_cache.end() != stat_cache.find(key)){
|
||||||
|
DelStat(key.c_str());
|
||||||
|
}else{
|
||||||
if(stat_cache.size() > CacheSize){
|
if(stat_cache.size() > CacheSize){
|
||||||
if(!TruncateCache()){
|
if(!TruncateCache()){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
struct stat st;
|
// make new
|
||||||
memset(&st, 0, sizeof(struct stat));
|
stat_cache_entry* ent = new stat_cache_entry();
|
||||||
|
memset(&(ent->stbuf), 0, sizeof(struct stat));
|
||||||
|
ent->hit_count = 0;
|
||||||
|
ent->cache_date = time(NULL); // Set time.
|
||||||
|
ent->isforce = false;
|
||||||
|
ent->noobjcache = true;
|
||||||
|
ent->meta.clear();
|
||||||
|
// add
|
||||||
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||||
stat_cache[key].stbuf = st;
|
stat_cache[key] = ent;
|
||||||
stat_cache[key].hit_count = 0;
|
|
||||||
stat_cache[key].cache_date = time(NULL); // Set time.
|
|
||||||
stat_cache[key].isforce = false;
|
|
||||||
stat_cache[key].noobjcache = true;
|
|
||||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
@ -310,25 +335,34 @@ bool StatCache::AddNoObjectCache(string& key)
|
|||||||
|
|
||||||
bool StatCache::TruncateCache(void)
|
bool StatCache::TruncateCache(void)
|
||||||
{
|
{
|
||||||
string path_to_delete;
|
if(0 == stat_cache.size()){
|
||||||
unsigned int lowest_hit_count = 0;
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||||
stat_cache_t::iterator iter;
|
|
||||||
for(iter = stat_cache.begin(); iter != stat_cache.end(); iter++) {
|
|
||||||
if(!lowest_hit_count) {
|
|
||||||
lowest_hit_count = (*iter).second.hit_count;
|
|
||||||
path_to_delete = (*iter).first;
|
|
||||||
}
|
|
||||||
if(lowest_hit_count > (*iter).second.hit_count){
|
|
||||||
lowest_hit_count = (*iter).second.hit_count;
|
|
||||||
path_to_delete = (*iter).first;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
stat_cache.erase(path_to_delete);
|
|
||||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
|
||||||
|
|
||||||
DPRNNN("truncate stat cache[path=%s]", path_to_delete.c_str());
|
time_t lowest_time = time(NULL) + 1;
|
||||||
|
stat_cache_t::iterator iter_to_delete = stat_cache.end();
|
||||||
|
stat_cache_t::iterator iter;
|
||||||
|
|
||||||
|
for(iter = stat_cache.begin(); iter != stat_cache.end(); iter++) {
|
||||||
|
if((*iter).second){
|
||||||
|
if(lowest_time > (*iter).second->cache_date){
|
||||||
|
lowest_time = (*iter).second->cache_date;
|
||||||
|
iter_to_delete = iter;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(stat_cache.end() != iter_to_delete){
|
||||||
|
DPRNNN("truncate stat cache[path=%s]", (*iter_to_delete).first.c_str());
|
||||||
|
if((*iter_to_delete).second){
|
||||||
|
delete (*iter_to_delete).second;
|
||||||
|
}
|
||||||
|
stat_cache.erase(iter_to_delete);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -341,8 +375,12 @@ bool StatCache::DelStat(const char* key)
|
|||||||
DPRNNN("delete stat cache entry[path=%s]", key);
|
DPRNNN("delete stat cache entry[path=%s]", key);
|
||||||
|
|
||||||
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||||
stat_cache_t::iterator iter = stat_cache.find(key);
|
|
||||||
if(iter != stat_cache.end()){
|
stat_cache_t::iterator iter;
|
||||||
|
if(stat_cache.end() != (iter = stat_cache.find(string(key)))){
|
||||||
|
if((*iter).second){
|
||||||
|
delete (*iter).second;
|
||||||
|
}
|
||||||
stat_cache.erase(iter);
|
stat_cache.erase(iter);
|
||||||
}
|
}
|
||||||
if(0 < strlen(key) && 0 != strcmp(key, "/")){
|
if(0 < strlen(key) && 0 != strcmp(key, "/")){
|
||||||
@ -354,11 +392,15 @@ bool StatCache::DelStat(const char* key)
|
|||||||
// If there is "path/" cache, delete it.
|
// If there is "path/" cache, delete it.
|
||||||
strpath += "/";
|
strpath += "/";
|
||||||
}
|
}
|
||||||
iter = stat_cache.find(strpath.c_str());
|
if(stat_cache.end() != (iter = stat_cache.find(strpath.c_str()))){
|
||||||
if(iter != stat_cache.end()){
|
if((*iter).second){
|
||||||
|
delete (*iter).second;
|
||||||
|
}
|
||||||
stat_cache.erase(iter);
|
stat_cache.erase(iter);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -20,7 +20,7 @@ struct stat_cache_entry {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::map<std::string, struct stat_cache_entry> stat_cache_t; // key=path
|
typedef std::map<std::string, stat_cache_entry*> stat_cache_t; // key=path
|
||||||
|
|
||||||
//
|
//
|
||||||
// Class
|
// Class
|
||||||
@ -37,6 +37,7 @@ class StatCache
|
|||||||
bool IsCacheNoObject;
|
bool IsCacheNoObject;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
void Clear(void);
|
||||||
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce);
|
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce);
|
||||||
// Truncate stat cache
|
// Truncate stat cache
|
||||||
bool TruncateCache(void);
|
bool TruncateCache(void);
|
||||||
|
258
src/curl.cpp
258
src/curl.cpp
@ -61,14 +61,17 @@ using namespace std;
|
|||||||
#define BODYDATA_RESIZE_APPEND_MIN (1 * 1024) // 1KB
|
#define BODYDATA_RESIZE_APPEND_MIN (1 * 1024) // 1KB
|
||||||
#define BODYDATA_RESIZE_APPEND_MID (1 * 1024 * 1024) // 1MB
|
#define BODYDATA_RESIZE_APPEND_MID (1 * 1024 * 1024) // 1MB
|
||||||
#define BODYDATA_RESIZE_APPEND_MAX (10 * 1024 * 1024) // 10MB
|
#define BODYDATA_RESIZE_APPEND_MAX (10 * 1024 * 1024) // 10MB
|
||||||
|
#define AJUST_BLOCK(bytes, block) (((bytes / block) + ((bytes % block) ? 1 : 0)) * block)
|
||||||
|
|
||||||
bool BodyData::Resize(size_t addbytes)
|
bool BodyData::Resize(size_t addbytes)
|
||||||
{
|
{
|
||||||
if(IsSafeSize(addbytes)){
|
if(IsSafeSize(addbytes)){
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// New size
|
// New size
|
||||||
size_t need_size = (lastpos + addbytes + 1) - bufsize;
|
size_t need_size = AJUST_BLOCK((lastpos + addbytes + 1) - bufsize, sizeof(off_t));
|
||||||
|
|
||||||
if(BODYDATA_RESIZE_APPEND_MAX < bufsize){
|
if(BODYDATA_RESIZE_APPEND_MAX < bufsize){
|
||||||
need_size = (BODYDATA_RESIZE_APPEND_MAX < need_size ? need_size : BODYDATA_RESIZE_APPEND_MAX);
|
need_size = (BODYDATA_RESIZE_APPEND_MAX < need_size ? need_size : BODYDATA_RESIZE_APPEND_MAX);
|
||||||
}else if(BODYDATA_RESIZE_APPEND_MID < bufsize){
|
}else if(BODYDATA_RESIZE_APPEND_MID < bufsize){
|
||||||
@ -79,11 +82,16 @@ bool BodyData::Resize(size_t addbytes)
|
|||||||
need_size = (BODYDATA_RESIZE_APPEND_MIN < need_size ? need_size : BODYDATA_RESIZE_APPEND_MIN);
|
need_size = (BODYDATA_RESIZE_APPEND_MIN < need_size ? need_size : BODYDATA_RESIZE_APPEND_MIN);
|
||||||
}
|
}
|
||||||
// realloc
|
// realloc
|
||||||
if(NULL == (text = (char*)realloc(text, (bufsize + need_size)))){
|
char* newtext;
|
||||||
|
if(NULL == (newtext = (char*)realloc(text, (bufsize + need_size)))){
|
||||||
DPRNCRIT("not enough memory (realloc returned NULL)");
|
DPRNCRIT("not enough memory (realloc returned NULL)");
|
||||||
|
free(text);
|
||||||
|
text = NULL;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
text = newtext;
|
||||||
bufsize += need_size;
|
bufsize += need_size;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -131,11 +139,12 @@ const char* BodyData::str(void) const
|
|||||||
#define MAX_MULTI_COPY_SOURCE_SIZE 524288000 // 500MB
|
#define MAX_MULTI_COPY_SOURCE_SIZE 524288000 // 500MB
|
||||||
|
|
||||||
pthread_mutex_t S3fsCurl::curl_handles_lock;
|
pthread_mutex_t S3fsCurl::curl_handles_lock;
|
||||||
pthread_mutex_t S3fsCurl::curl_share_lock;
|
pthread_mutex_t S3fsCurl::curl_share_lock[SHARE_MUTEX_MAX];
|
||||||
pthread_mutex_t* S3fsCurl::crypt_mutex = NULL;
|
pthread_mutex_t* S3fsCurl::crypt_mutex = NULL;
|
||||||
bool S3fsCurl::is_initglobal_done = false;
|
bool S3fsCurl::is_initglobal_done = false;
|
||||||
CURLSH* S3fsCurl::hCurlShare = NULL;
|
CURLSH* S3fsCurl::hCurlShare = NULL;
|
||||||
bool S3fsCurl::is_dns_cache = true; // default
|
bool S3fsCurl::is_dns_cache = true; // default
|
||||||
|
bool S3fsCurl::is_ssl_session_cache= true; // default
|
||||||
long S3fsCurl::connect_timeout = 10; // default
|
long S3fsCurl::connect_timeout = 10; // default
|
||||||
time_t S3fsCurl::readwrite_timeout = 30; // default
|
time_t S3fsCurl::readwrite_timeout = 30; // default
|
||||||
int S3fsCurl::retries = 3; // default
|
int S3fsCurl::retries = 3; // default
|
||||||
@ -163,7 +172,10 @@ bool S3fsCurl::InitS3fsCurl(const char* MimeFile)
|
|||||||
if(0 != pthread_mutex_init(&S3fsCurl::curl_handles_lock, NULL)){
|
if(0 != pthread_mutex_init(&S3fsCurl::curl_handles_lock, NULL)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(0 != pthread_mutex_init(&S3fsCurl::curl_share_lock, NULL)){
|
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)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(!S3fsCurl::InitMimeType(MimeFile)){
|
if(!S3fsCurl::InitMimeType(MimeFile)){
|
||||||
@ -186,15 +198,18 @@ bool S3fsCurl::DestroyS3fsCurl(void)
|
|||||||
int result = true;
|
int result = true;
|
||||||
|
|
||||||
if(!S3fsCurl::DestroyCryptMutex()){
|
if(!S3fsCurl::DestroyCryptMutex()){
|
||||||
return false;
|
result = false;
|
||||||
}
|
}
|
||||||
if(!S3fsCurl::DestroyShareCurl()){
|
if(!S3fsCurl::DestroyShareCurl()){
|
||||||
return false;
|
result = false;
|
||||||
}
|
}
|
||||||
if(!S3fsCurl::DestroyGlobalCurl()){
|
if(!S3fsCurl::DestroyGlobalCurl()){
|
||||||
return false;
|
result = false;
|
||||||
}
|
}
|
||||||
if(0 != pthread_mutex_destroy(&S3fsCurl::curl_share_lock)){
|
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])){
|
||||||
result = false;
|
result = false;
|
||||||
}
|
}
|
||||||
if(0 != pthread_mutex_destroy(&S3fsCurl::curl_handles_lock)){
|
if(0 != pthread_mutex_destroy(&S3fsCurl::curl_handles_lock)){
|
||||||
@ -230,12 +245,9 @@ bool S3fsCurl::InitShareCurl(void)
|
|||||||
{
|
{
|
||||||
CURLSHcode nSHCode;
|
CURLSHcode nSHCode;
|
||||||
|
|
||||||
if(!S3fsCurl::is_dns_cache){
|
if(!S3fsCurl::is_dns_cache && !S3fsCurl::is_ssl_session_cache){
|
||||||
return false;
|
DPRN("Curl does not share DNS data.");
|
||||||
}
|
return true;
|
||||||
if(!S3fsCurl::is_initglobal_done){
|
|
||||||
DPRN("could not initialize global curl.");
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if(S3fsCurl::hCurlShare){
|
if(S3fsCurl::hCurlShare){
|
||||||
DPRN("already initiated.");
|
DPRN("already initiated.");
|
||||||
@ -253,11 +265,19 @@ bool S3fsCurl::InitShareCurl(void)
|
|||||||
DPRN("curl_share_setopt(UNLOCKFUNC) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
DPRN("curl_share_setopt(UNLOCKFUNC) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
if(!S3fsCurl::is_dns_cache){
|
||||||
if(CURLSHE_OK != (nSHCode = curl_share_setopt(S3fsCurl::hCurlShare, CURLSHOPT_SHARE, CURL_LOCK_DATA_DNS))){
|
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));
|
DPRN("curl_share_setopt(DNS) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(CURLSHE_OK != (nSHCode = curl_share_setopt(S3fsCurl::hCurlShare, CURLSHOPT_USERDATA, (void*)&S3fsCurl::curl_share_lock))){
|
}
|
||||||
|
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]))){
|
||||||
DPRN("curl_share_setopt(USERDATA) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
DPRN("curl_share_setopt(USERDATA) returns %d(%s)", nSHCode, curl_share_strerror(nSHCode));
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -266,14 +286,11 @@ bool S3fsCurl::InitShareCurl(void)
|
|||||||
|
|
||||||
bool S3fsCurl::DestroyShareCurl(void)
|
bool S3fsCurl::DestroyShareCurl(void)
|
||||||
{
|
{
|
||||||
if(!S3fsCurl::is_initglobal_done){
|
|
||||||
DPRN("already destroy global curl.");
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
if(!S3fsCurl::hCurlShare){
|
if(!S3fsCurl::hCurlShare){
|
||||||
if(S3fsCurl::is_dns_cache){
|
if(!S3fsCurl::is_dns_cache && !S3fsCurl::is_ssl_session_cache){
|
||||||
DPRN("already destroy share curl.");
|
return true;
|
||||||
}
|
}
|
||||||
|
DPRN("already destroy share curl.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if(CURLSHE_OK != curl_share_cleanup(S3fsCurl::hCurlShare)){
|
if(CURLSHE_OK != curl_share_cleanup(S3fsCurl::hCurlShare)){
|
||||||
@ -285,17 +302,27 @@ bool S3fsCurl::DestroyShareCurl(void)
|
|||||||
|
|
||||||
void S3fsCurl::LockCurlShare(CURL* handle, curl_lock_data nLockData, curl_lock_access laccess, void* useptr)
|
void S3fsCurl::LockCurlShare(CURL* handle, curl_lock_data nLockData, curl_lock_access laccess, void* useptr)
|
||||||
{
|
{
|
||||||
if(hCurlShare && useptr && CURL_LOCK_DATA_DNS == nLockData){
|
if(!hCurlShare){
|
||||||
|
return;
|
||||||
|
}
|
||||||
pthread_mutex_t* lockmutex = static_cast<pthread_mutex_t*>(useptr);
|
pthread_mutex_t* lockmutex = static_cast<pthread_mutex_t*>(useptr);
|
||||||
pthread_mutex_lock(lockmutex);
|
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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void S3fsCurl::UnlockCurlShare(CURL* handle, curl_lock_data nLockData, void* useptr)
|
void S3fsCurl::UnlockCurlShare(CURL* handle, curl_lock_data nLockData, void* useptr)
|
||||||
{
|
{
|
||||||
if(hCurlShare && useptr && CURL_LOCK_DATA_DNS == nLockData){
|
if(!hCurlShare){
|
||||||
|
return;
|
||||||
|
}
|
||||||
pthread_mutex_t* lockmutex = static_cast<pthread_mutex_t*>(useptr);
|
pthread_mutex_t* lockmutex = static_cast<pthread_mutex_t*>(useptr);
|
||||||
pthread_mutex_unlock(lockmutex);
|
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]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -341,6 +368,7 @@ bool S3fsCurl::DestroyCryptMutex(void)
|
|||||||
for(int cnt = 0; cnt < CRYPTO_num_locks(); cnt++){
|
for(int cnt = 0; cnt < CRYPTO_num_locks(); cnt++){
|
||||||
pthread_mutex_destroy(&S3fsCurl::crypt_mutex[cnt]);
|
pthread_mutex_destroy(&S3fsCurl::crypt_mutex[cnt]);
|
||||||
}
|
}
|
||||||
|
CRYPTO_cleanup_all_ex_data();
|
||||||
free(S3fsCurl::crypt_mutex);
|
free(S3fsCurl::crypt_mutex);
|
||||||
S3fsCurl::crypt_mutex = NULL;
|
S3fsCurl::crypt_mutex = NULL;
|
||||||
|
|
||||||
@ -554,6 +582,9 @@ bool S3fsCurl::LocateBundle(void)
|
|||||||
if(BF.good()){
|
if(BF.good()){
|
||||||
BF.close();
|
BF.close();
|
||||||
S3fsCurl::curl_ca_bundle.assign("/etc/pki/tls/certs/ca-bundle.crt");
|
S3fsCurl::curl_ca_bundle.assign("/etc/pki/tls/certs/ca-bundle.crt");
|
||||||
|
}else{
|
||||||
|
DPRN("%s: /etc/pki/tls/certs/ca-bundle.crt is not readable", program_name.c_str());
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -683,6 +714,13 @@ bool S3fsCurl::SetDnsCache(bool isCache)
|
|||||||
return old;
|
return old;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool S3fsCurl::SetSslSessionCache(bool isCache)
|
||||||
|
{
|
||||||
|
bool old = S3fsCurl::is_ssl_session_cache;
|
||||||
|
S3fsCurl::is_ssl_session_cache = isCache;
|
||||||
|
return old;
|
||||||
|
}
|
||||||
|
|
||||||
long S3fsCurl::SetConnectTimeout(long timeout)
|
long S3fsCurl::SetConnectTimeout(long timeout)
|
||||||
{
|
{
|
||||||
long old = S3fsCurl::connect_timeout;
|
long old = S3fsCurl::connect_timeout;
|
||||||
@ -829,7 +867,6 @@ int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta,
|
|||||||
string upload_id;
|
string upload_id;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int fd2;
|
int fd2;
|
||||||
FILE* file;
|
|
||||||
etaglist_t list;
|
etaglist_t list;
|
||||||
off_t remaining_bytes;
|
off_t remaining_bytes;
|
||||||
unsigned char* buf;
|
unsigned char* buf;
|
||||||
@ -838,7 +875,7 @@ int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta,
|
|||||||
FPRNNN("[tpath=%s][fd=%d]", SAFESTRPTR(tpath), fd);
|
FPRNNN("[tpath=%s][fd=%d]", SAFESTRPTR(tpath), fd);
|
||||||
|
|
||||||
// duplicate fd
|
// duplicate fd
|
||||||
if(-1 == (fd2 = dup(fd)) || 0 != lseek(fd2, 0, SEEK_SET) || NULL == (file = fdopen(fd2, "rb"))){
|
if(-1 == (fd2 = dup(fd)) || 0 != lseek(fd2, 0, SEEK_SET)){
|
||||||
DPRN("Cloud not duplicate file discriptor(errno=%d)", errno);
|
DPRN("Cloud not duplicate file discriptor(errno=%d)", errno);
|
||||||
if(-1 != fd2){
|
if(-1 != fd2){
|
||||||
close(fd2);
|
close(fd2);
|
||||||
@ -847,21 +884,12 @@ int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta,
|
|||||||
}
|
}
|
||||||
if(-1 == fstat(fd2, &st)){
|
if(-1 == fstat(fd2, &st)){
|
||||||
DPRN("Invalid file discriptor(errno=%d)", errno);
|
DPRN("Invalid file discriptor(errno=%d)", errno);
|
||||||
fclose(file);
|
close(fd2);
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make Tempolary buf(maximum size + 4)
|
|
||||||
if(NULL == (buf = (unsigned char*)malloc(sizeof(unsigned char) * (MULTIPART_SIZE + 4)))){
|
|
||||||
DPRNCRIT("Could not allocate memory for buffer");
|
|
||||||
fclose(file);
|
|
||||||
S3FS_FUSE_EXIT();
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(0 != (result = s3fscurl.PreMultipartPostRequest(tpath, meta, upload_id, ow_sse_flg))){
|
if(0 != (result = s3fscurl.PreMultipartPostRequest(tpath, meta, upload_id, ow_sse_flg))){
|
||||||
free(buf);
|
close(fd2);
|
||||||
fclose(file);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
s3fscurl.DestroyCurlHandle();
|
s3fscurl.DestroyCurlHandle();
|
||||||
@ -891,8 +919,7 @@ int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta,
|
|||||||
// initiate upload part for parallel
|
// initiate upload part for parallel
|
||||||
if(0 != (result = s3fscurl_para->UploadMultipartPostSetup(tpath, list.size(), upload_id))){
|
if(0 != (result = s3fscurl_para->UploadMultipartPostSetup(tpath, list.size(), upload_id))){
|
||||||
DPRN("failed uploading part setup(%d)", result);
|
DPRN("failed uploading part setup(%d)", result);
|
||||||
free(buf);
|
close(fd2);
|
||||||
fclose(file);
|
|
||||||
delete s3fscurl_para;
|
delete s3fscurl_para;
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -900,8 +927,7 @@ int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta,
|
|||||||
// set into parallel object
|
// set into parallel object
|
||||||
if(!curlmulti.SetS3fsCurlObject(s3fscurl_para)){
|
if(!curlmulti.SetS3fsCurlObject(s3fscurl_para)){
|
||||||
DPRN("Could not make curl object into multi curl(%s).", tpath);
|
DPRN("Could not make curl object into multi curl(%s).", tpath);
|
||||||
free(buf);
|
close(fd2);
|
||||||
fclose(file);
|
|
||||||
delete s3fscurl_para;
|
delete s3fscurl_para;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
@ -916,8 +942,7 @@ int S3fsCurl::ParallelMultipartUploadRequest(const char* tpath, headers_t& meta,
|
|||||||
// reinit for loop.
|
// reinit for loop.
|
||||||
curlmulti.Clear();
|
curlmulti.Clear();
|
||||||
}
|
}
|
||||||
free(buf);
|
close(fd2);
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
if(0 != (result = s3fscurl.CompleteMultipartPostRequest(tpath, upload_id, list))){
|
if(0 != (result = s3fscurl.CompleteMultipartPostRequest(tpath, upload_id, list))){
|
||||||
return result;
|
return result;
|
||||||
@ -1026,7 +1051,7 @@ bool S3fsCurl::ResetHandle(void)
|
|||||||
if(S3fsCurl::curl_ca_bundle.size() != 0){
|
if(S3fsCurl::curl_ca_bundle.size() != 0){
|
||||||
curl_easy_setopt(hCurl, CURLOPT_CAINFO, S3fsCurl::curl_ca_bundle.c_str());
|
curl_easy_setopt(hCurl, CURLOPT_CAINFO, S3fsCurl::curl_ca_bundle.c_str());
|
||||||
}
|
}
|
||||||
if(S3fsCurl::is_dns_cache && S3fsCurl::hCurlShare){
|
if((S3fsCurl::is_dns_cache || S3fsCurl::is_ssl_session_cache) && S3fsCurl::hCurlShare){
|
||||||
curl_easy_setopt(hCurl, CURLOPT_SHARE, S3fsCurl::hCurlShare);
|
curl_easy_setopt(hCurl, CURLOPT_SHARE, S3fsCurl::hCurlShare);
|
||||||
}
|
}
|
||||||
if(S3fsCurl::is_verbose){
|
if(S3fsCurl::is_verbose){
|
||||||
@ -1052,7 +1077,6 @@ bool S3fsCurl::CreateCurlHandle(bool force)
|
|||||||
DPRN("could not destroy handle.");
|
DPRN("could not destroy handle.");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
ClearInternalData();
|
|
||||||
DPRN("already has handle, so destroied it.");
|
DPRN("already has handle, so destroied it.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1118,6 +1142,8 @@ bool S3fsCurl::ClearInternalData(void)
|
|||||||
b_partdata_size = 0;
|
b_partdata_size = 0;
|
||||||
partdata.clear();
|
partdata.clear();
|
||||||
|
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1414,12 +1440,7 @@ int S3fsCurl::RequestPerform(void)
|
|||||||
if(!S3fsCurl::LocateBundle()){
|
if(!S3fsCurl::LocateBundle()){
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
}
|
}
|
||||||
if(0 != S3fsCurl::curl_ca_bundle.size()){
|
break; // retry with CAINFO
|
||||||
retrycnt++;
|
|
||||||
curl_easy_setopt(hCurl, CURLOPT_CAINFO, S3fsCurl::curl_ca_bundle.c_str());
|
|
||||||
// break for switch-case, and continue loop.
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
DPRNCRIT("curlCode: %d msg: %s", curlCode, curl_easy_strerror(curlCode));
|
DPRNCRIT("curlCode: %d msg: %s", curlCode, curl_easy_strerror(curlCode));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
@ -1535,6 +1556,7 @@ string S3fsCurl::CalcSignature(string method, string strMD5, string content_type
|
|||||||
}
|
}
|
||||||
// Too many write attempts
|
// Too many write attempts
|
||||||
DPRNNN("Failure during BIO_write, returning null String");
|
DPRNNN("Failure during BIO_write, returning null String");
|
||||||
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
||||||
BIO_free_all(b64);
|
BIO_free_all(b64);
|
||||||
Signature.clear();
|
Signature.clear();
|
||||||
return Signature;
|
return Signature;
|
||||||
@ -1542,6 +1564,7 @@ string S3fsCurl::CalcSignature(string method, string strMD5, string content_type
|
|||||||
}else{
|
}else{
|
||||||
// If not a retry then it is an error
|
// If not a retry then it is an error
|
||||||
DPRNNN("Failure during BIO_write, returning null String");
|
DPRNNN("Failure during BIO_write, returning null String");
|
||||||
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
||||||
BIO_free_all(b64);
|
BIO_free_all(b64);
|
||||||
Signature.clear();
|
Signature.clear();
|
||||||
return Signature;
|
return Signature;
|
||||||
@ -1563,6 +1586,7 @@ string S3fsCurl::CalcSignature(string method, string strMD5, string content_type
|
|||||||
ret = BIO_flush(b64);
|
ret = BIO_flush(b64);
|
||||||
if(ret <= 0){
|
if(ret <= 0){
|
||||||
DPRNNN("Failure during BIO_flush, returning null String");
|
DPRNNN("Failure during BIO_flush, returning null String");
|
||||||
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
||||||
BIO_free_all(b64);
|
BIO_free_all(b64);
|
||||||
Signature.clear();
|
Signature.clear();
|
||||||
return Signature;
|
return Signature;
|
||||||
@ -1570,10 +1594,9 @@ string S3fsCurl::CalcSignature(string method, string strMD5, string content_type
|
|||||||
|
|
||||||
BUF_MEM *bptr;
|
BUF_MEM *bptr;
|
||||||
BIO_get_mem_ptr(b64, &bptr);
|
BIO_get_mem_ptr(b64, &bptr);
|
||||||
|
Signature.assign(bptr->data, bptr->length - 1);
|
||||||
|
|
||||||
Signature.resize(bptr->length - 1);
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
||||||
memcpy(&Signature[0], bptr->data, bptr->length-1);
|
|
||||||
|
|
||||||
BIO_free_all(b64);
|
BIO_free_all(b64);
|
||||||
|
|
||||||
return Signature;
|
return Signature;
|
||||||
@ -1589,8 +1612,12 @@ bool S3fsCurl::GetUploadId(string& upload_id)
|
|||||||
}
|
}
|
||||||
upload_id.clear();
|
upload_id.clear();
|
||||||
|
|
||||||
xmlDocPtr doc = xmlReadMemory(bodydata->str(), bodydata->size(), "", NULL, 0);
|
xmlDocPtr doc;
|
||||||
if(NULL == doc || NULL == doc->children){
|
if(NULL == (doc = xmlReadMemory(bodydata->str(), bodydata->size(), "", NULL, 0))){
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
if(NULL == doc->children){
|
||||||
|
S3FS_XMLFREEDOC(doc);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
for(xmlNodePtr cur_node = doc->children->children; NULL != cur_node; cur_node = cur_node->next){
|
for(xmlNodePtr cur_node = doc->children->children; NULL != cur_node; cur_node = cur_node->next){
|
||||||
@ -1614,7 +1641,7 @@ bool S3fsCurl::GetUploadId(string& upload_id)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
xmlFreeDoc(doc);
|
S3FS_XMLFREEDOC(doc);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -2045,7 +2072,6 @@ int S3fsCurl::CheckBucket(void)
|
|||||||
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
string("Authorization: AWS " + AWSAccessKeyId + ":" +
|
||||||
CalcSignature("GET", "", "", date, resource)).c_str());
|
CalcSignature("GET", "", "", date, resource)).c_str());
|
||||||
}
|
}
|
||||||
|
|
||||||
// setopt
|
// setopt
|
||||||
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
curl_easy_setopt(hCurl, CURLOPT_URL, url.c_str());
|
||||||
curl_easy_setopt(hCurl, CURLOPT_FAILONERROR, true);
|
curl_easy_setopt(hCurl, CURLOPT_FAILONERROR, true);
|
||||||
@ -2580,16 +2606,14 @@ int S3fsCurl::MultipartUploadRequest(const char* tpath, headers_t& meta, int fd,
|
|||||||
string upload_id;
|
string upload_id;
|
||||||
struct stat st;
|
struct stat st;
|
||||||
int fd2;
|
int fd2;
|
||||||
FILE* file;
|
|
||||||
etaglist_t list;
|
etaglist_t list;
|
||||||
off_t remaining_bytes;
|
off_t remaining_bytes;
|
||||||
off_t chunk;
|
off_t chunk;
|
||||||
unsigned char* buf;
|
|
||||||
|
|
||||||
FPRNNN("[tpath=%s][fd=%d]", SAFESTRPTR(tpath), fd);
|
FPRNNN("[tpath=%s][fd=%d]", SAFESTRPTR(tpath), fd);
|
||||||
|
|
||||||
// duplicate fd
|
// duplicate fd
|
||||||
if(-1 == (fd2 = dup(fd)) || 0 != lseek(fd2, 0, SEEK_SET) || NULL == (file = fdopen(fd2, "rb"))){
|
if(-1 == (fd2 = dup(fd)) || 0 != lseek(fd2, 0, SEEK_SET)){
|
||||||
DPRN("Cloud not duplicate file discriptor(errno=%d)", errno);
|
DPRN("Cloud not duplicate file discriptor(errno=%d)", errno);
|
||||||
if(-1 != fd2){
|
if(-1 != fd2){
|
||||||
close(fd2);
|
close(fd2);
|
||||||
@ -2598,21 +2622,12 @@ int S3fsCurl::MultipartUploadRequest(const char* tpath, headers_t& meta, int fd,
|
|||||||
}
|
}
|
||||||
if(-1 == fstat(fd2, &st)){
|
if(-1 == fstat(fd2, &st)){
|
||||||
DPRN("Invalid file discriptor(errno=%d)", errno);
|
DPRN("Invalid file discriptor(errno=%d)", errno);
|
||||||
fclose(file);
|
close(fd2);
|
||||||
return -errno;
|
return -errno;
|
||||||
}
|
}
|
||||||
|
|
||||||
// make Tempolary buf(maximum size + 4)
|
|
||||||
if(NULL == (buf = (unsigned char*)malloc(sizeof(unsigned char) * (MULTIPART_SIZE + 4)))){
|
|
||||||
DPRNCRIT("Could not allocate memory for buffer");
|
|
||||||
fclose(file);
|
|
||||||
S3FS_FUSE_EXIT();
|
|
||||||
return -ENOMEM;
|
|
||||||
}
|
|
||||||
|
|
||||||
if(0 != (result = PreMultipartPostRequest(tpath, meta, upload_id, ow_sse_flg))){
|
if(0 != (result = PreMultipartPostRequest(tpath, meta, upload_id, ow_sse_flg))){
|
||||||
free(buf);
|
close(fd2);
|
||||||
fclose(file);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
DestroyCurlHandle();
|
DestroyCurlHandle();
|
||||||
@ -2632,15 +2647,13 @@ int S3fsCurl::MultipartUploadRequest(const char* tpath, headers_t& meta, int fd,
|
|||||||
// upload part
|
// upload part
|
||||||
if(0 != (result = UploadMultipartPostRequest(tpath, (list.size() + 1), upload_id))){
|
if(0 != (result = UploadMultipartPostRequest(tpath, (list.size() + 1), upload_id))){
|
||||||
DPRN("failed uploading part(%d)", result);
|
DPRN("failed uploading part(%d)", result);
|
||||||
free(buf);
|
close(fd2);
|
||||||
fclose(file);
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
list.push_back(partdata.etag);
|
list.push_back(partdata.etag);
|
||||||
DestroyCurlHandle();
|
DestroyCurlHandle();
|
||||||
}
|
}
|
||||||
free(buf);
|
close(fd2);
|
||||||
fclose(file);
|
|
||||||
|
|
||||||
if(0 != (result = CompleteMultipartPostRequest(tpath, upload_id, list))){
|
if(0 != (result = CompleteMultipartPostRequest(tpath, upload_id, list))){
|
||||||
return result;
|
return result;
|
||||||
@ -2694,7 +2707,7 @@ int S3fsCurl::MultipartRenameRequest(const char* from, const char* to, headers_t
|
|||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
// Class S3fsMultiCurl
|
// Class S3fsMultiCurl
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
#define MAX_MULTI_HEADREQ 500 // default: max request count in readdir curl_multi.
|
#define MAX_MULTI_HEADREQ 20 // default: max request count in readdir curl_multi.
|
||||||
|
|
||||||
//-------------------------------------------------------------------
|
//-------------------------------------------------------------------
|
||||||
// Class method for S3fsMultiCurl
|
// Class method for S3fsMultiCurl
|
||||||
@ -2720,27 +2733,35 @@ S3fsMultiCurl::~S3fsMultiCurl()
|
|||||||
Clear();
|
Clear();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool S3fsMultiCurl::Clear(void)
|
bool S3fsMultiCurl::ClearEx(bool is_all)
|
||||||
{
|
{
|
||||||
|
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.
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if(hMulti){
|
if(hMulti){
|
||||||
curl_multi_cleanup(hMulti);
|
curl_multi_cleanup(hMulti);
|
||||||
hMulti = NULL;
|
hMulti = NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
s3fscurlmap_t::iterator iter;
|
if(is_all){
|
||||||
for(iter = cMap_all.begin(); iter != cMap_all.end(); iter++){
|
for(iter = cMap_all.begin(); iter != cMap_all.end(); cMap_all.erase(iter++)){
|
||||||
S3fsCurl* s3fscurl = (*iter).second;
|
S3fsCurl* s3fscurl = (*iter).second;
|
||||||
s3fscurl->DestroyCurlHandle();
|
s3fscurl->DestroyCurlHandle();
|
||||||
delete s3fscurl;
|
delete s3fscurl;
|
||||||
}
|
}
|
||||||
cMap_all.clear();
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
for(iter = cMap_req.begin(); iter != cMap_req.end(); iter++){
|
|
||||||
S3fsCurl* s3fscurl = (*iter).second;
|
|
||||||
s3fscurl->DestroyCurlHandle();
|
|
||||||
delete s3fscurl;
|
|
||||||
}
|
|
||||||
cMap_req.clear();
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2760,6 +2781,10 @@ S3fsMultiRetryCallback S3fsMultiCurl::SetRetryCallback(S3fsMultiRetryCallback fu
|
|||||||
|
|
||||||
bool S3fsMultiCurl::SetS3fsCurlObject(S3fsCurl* s3fscurl)
|
bool S3fsMultiCurl::SetS3fsCurlObject(S3fsCurl* s3fscurl)
|
||||||
{
|
{
|
||||||
|
if(hMulti){
|
||||||
|
DPRN("Internal error: hMulti is not null");
|
||||||
|
return false;
|
||||||
|
}
|
||||||
if(!s3fscurl){
|
if(!s3fscurl){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -2842,40 +2867,51 @@ int S3fsMultiCurl::MultiRead(void)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
hCurl = msg->easy_handle;
|
hCurl = msg->easy_handle;
|
||||||
|
if(cMap_req.end() != cMap_req.find(hCurl)){
|
||||||
s3fscurl = cMap_req[hCurl];
|
s3fscurl = cMap_req[hCurl];
|
||||||
|
}else{
|
||||||
|
s3fscurl = NULL;
|
||||||
|
}
|
||||||
retrycurl= NULL;
|
retrycurl= NULL;
|
||||||
|
|
||||||
if(CURLE_OK == msg->data.result && s3fscurl){
|
if(s3fscurl){
|
||||||
|
if(CURLE_OK == msg->data.result){
|
||||||
long responseCode;
|
long responseCode;
|
||||||
if(s3fscurl->GetResponseCode(responseCode) && 400 > responseCode){
|
if(s3fscurl->GetResponseCode(responseCode) && 400 > responseCode){
|
||||||
// add into stat cache
|
// add into stat cache
|
||||||
if(SuccessCallback && !SuccessCallback(s3fscurl)){
|
if(SuccessCallback && !SuccessCallback(s3fscurl)){
|
||||||
DPRNNN("S3fsMultiCurl::MultiRead: error from callback function(%s).", s3fscurl->base_path.c_str());
|
DPRNNN("error from callback function(%s).", s3fscurl->base_path.c_str());
|
||||||
}
|
}
|
||||||
}else{
|
}else{
|
||||||
// This case is directory object("dir", "non dir object", "_$folder$", etc)
|
// This case is directory object("dir", "non dir object", "_$folder$", etc)
|
||||||
DPRNINFO("S3fsMultiCurl::MultiRead: failed a request(%s)", s3fscurl->base_path.c_str());
|
DPRNINFO("failed a request(%s)", s3fscurl->base_path.c_str());
|
||||||
}
|
}
|
||||||
|
cMap_req.erase(hCurl);
|
||||||
|
curl_multi_remove_handle(hMulti, hCurl);
|
||||||
|
|
||||||
|
s3fscurl->DestroyCurlHandle();
|
||||||
|
delete s3fscurl;
|
||||||
|
|
||||||
}else{
|
}else{
|
||||||
DPRNNN("failed to read(remaining: %d code: %d msg: %s), so retry this.",
|
DPRNNN("failed to read(remaining: %d code: %d msg: %s), so retry this.",
|
||||||
remaining_messages, msg->data.result, curl_easy_strerror(msg->data.result));
|
remaining_messages, msg->data.result, curl_easy_strerror(msg->data.result));
|
||||||
|
|
||||||
|
cMap_req.erase(hCurl);
|
||||||
|
curl_multi_remove_handle(hMulti, hCurl);
|
||||||
|
|
||||||
// For retry
|
// For retry
|
||||||
if(RetryCallback){
|
if(RetryCallback){
|
||||||
retrycurl = RetryCallback(s3fscurl);
|
retrycurl = RetryCallback(s3fscurl);
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Cleanup this curl object and set retrying object(if there is).
|
|
||||||
curl_multi_remove_handle(hMulti, hCurl);
|
|
||||||
cMap_req.erase(hCurl);
|
|
||||||
if(s3fscurl && s3fscurl != retrycurl){
|
|
||||||
delete s3fscurl; // with destroy curl handle.
|
|
||||||
}
|
|
||||||
if(retrycurl){
|
|
||||||
cMap_all[retrycurl->hCurl] = retrycurl;
|
cMap_all[retrycurl->hCurl] = retrycurl;
|
||||||
}
|
}
|
||||||
|
if(s3fscurl != retrycurl){
|
||||||
|
s3fscurl->DestroyCurlHandle();
|
||||||
|
delete s3fscurl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
assert(false);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -2888,7 +2924,8 @@ int S3fsMultiCurl::Request(void)
|
|||||||
FPRNNN("[count=%zu]", cMap_all.size());
|
FPRNNN("[count=%zu]", cMap_all.size());
|
||||||
|
|
||||||
if(hMulti){
|
if(hMulti){
|
||||||
Clear();
|
DPRNNN("Warning: hMulti is not null, thus clear itself.");
|
||||||
|
ClearEx(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Make request list.
|
// Make request list.
|
||||||
@ -2930,8 +2967,8 @@ int S3fsMultiCurl::Request(void)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// cleanup
|
// Cleanup curl handle in multi handle
|
||||||
curl_multi_cleanup(hMulti);
|
ClearEx(false);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -3084,6 +3121,8 @@ struct curl_slist* AdditionalHeader::AddHeader(struct curl_slist* list, const ch
|
|||||||
// Adding header
|
// Adding header
|
||||||
list = curl_slist_sort_insert(list, slistval.c_str());
|
list = curl_slist_sort_insert(list, slistval.c_str());
|
||||||
}
|
}
|
||||||
|
meta.clear();
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
return list;
|
return list;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3141,14 +3180,14 @@ string GetContentMD5(int fd)
|
|||||||
BIO_write(b64, md5hex, MD5_DIGEST_LENGTH);
|
BIO_write(b64, md5hex, MD5_DIGEST_LENGTH);
|
||||||
free(md5hex);
|
free(md5hex);
|
||||||
if(1 != BIO_flush(b64)){
|
if(1 != BIO_flush(b64)){
|
||||||
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
||||||
BIO_free_all(b64);
|
BIO_free_all(b64);
|
||||||
return string("");
|
return string("");
|
||||||
}
|
}
|
||||||
BIO_get_mem_ptr(b64, &bptr);
|
BIO_get_mem_ptr(b64, &bptr);
|
||||||
|
Signature.assign(bptr->data, bptr->length - 1);
|
||||||
|
|
||||||
Signature.resize(bptr->length - 1);
|
CRYPTO_free_ex_data(CRYPTO_EX_INDEX_BIO, b64, &b64->ex_data);
|
||||||
memcpy(&Signature[0], bptr->data, bptr->length - 1);
|
|
||||||
|
|
||||||
BIO_free_all(b64);
|
BIO_free_all(b64);
|
||||||
|
|
||||||
return Signature;
|
return Signature;
|
||||||
@ -3159,12 +3198,15 @@ unsigned char* md5hexsum(int fd, off_t start, ssize_t size)
|
|||||||
MD5_CTX c;
|
MD5_CTX c;
|
||||||
char buf[512];
|
char buf[512];
|
||||||
ssize_t bytes;
|
ssize_t bytes;
|
||||||
unsigned char* result = (unsigned char*)malloc(MD5_DIGEST_LENGTH);
|
unsigned char* result;
|
||||||
|
|
||||||
// seek to top of file.
|
// seek to top of file.
|
||||||
if(-1 == lseek(fd, start, SEEK_SET)){
|
if(-1 == lseek(fd, start, SEEK_SET)){
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
|
if(NULL == (result = (unsigned char*)malloc(MD5_DIGEST_LENGTH))){
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
memset(buf, 0, 512);
|
memset(buf, 0, 512);
|
||||||
MD5_Init(&c);
|
MD5_Init(&c);
|
||||||
|
12
src/curl.h
12
src/curl.h
@ -99,6 +99,11 @@ class S3fsMultiCurl;
|
|||||||
//----------------------------------------------
|
//----------------------------------------------
|
||||||
// class S3fsCurl
|
// class S3fsCurl
|
||||||
//----------------------------------------------
|
//----------------------------------------------
|
||||||
|
// share
|
||||||
|
#define SHARE_MUTEX_DNS 0
|
||||||
|
#define SHARE_MUTEX_SSL_SESSION 1
|
||||||
|
#define SHARE_MUTEX_MAX 2
|
||||||
|
|
||||||
// internal use struct for openssl
|
// internal use struct for openssl
|
||||||
struct CRYPTO_dynlock_value
|
struct CRYPTO_dynlock_value
|
||||||
{
|
{
|
||||||
@ -130,11 +135,12 @@ class S3fsCurl
|
|||||||
|
|
||||||
// class variables
|
// class variables
|
||||||
static pthread_mutex_t curl_handles_lock;
|
static pthread_mutex_t curl_handles_lock;
|
||||||
static pthread_mutex_t curl_share_lock;
|
static pthread_mutex_t curl_share_lock[SHARE_MUTEX_MAX];
|
||||||
static pthread_mutex_t* crypt_mutex;
|
static pthread_mutex_t* crypt_mutex;
|
||||||
static bool is_initglobal_done;
|
static bool is_initglobal_done;
|
||||||
static CURLSH* hCurlShare;
|
static CURLSH* hCurlShare;
|
||||||
static bool is_dns_cache;
|
static bool is_dns_cache;
|
||||||
|
static bool is_ssl_session_cache;
|
||||||
static long connect_timeout;
|
static long connect_timeout;
|
||||||
static time_t readwrite_timeout;
|
static time_t readwrite_timeout;
|
||||||
static int retries;
|
static int retries;
|
||||||
@ -233,6 +239,7 @@ class S3fsCurl
|
|||||||
// class methods(valiables)
|
// class methods(valiables)
|
||||||
static std::string LookupMimeType(std::string name);
|
static std::string LookupMimeType(std::string name);
|
||||||
static bool SetDnsCache(bool isCache);
|
static bool SetDnsCache(bool isCache);
|
||||||
|
static bool SetSslSessionCache(bool isCache);
|
||||||
static long SetConnectTimeout(long timeout);
|
static long SetConnectTimeout(long timeout);
|
||||||
static time_t SetReadwriteTimeout(time_t timeout);
|
static time_t SetReadwriteTimeout(time_t timeout);
|
||||||
static time_t GetReadwriteTimeout(void) { return S3fsCurl::readwrite_timeout; }
|
static time_t GetReadwriteTimeout(void) { return S3fsCurl::readwrite_timeout; }
|
||||||
@ -314,6 +321,7 @@ class S3fsMultiCurl
|
|||||||
S3fsMultiRetryCallback RetryCallback;
|
S3fsMultiRetryCallback RetryCallback;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
bool ClearEx(bool is_all);
|
||||||
int MultiPerform(void);
|
int MultiPerform(void);
|
||||||
int MultiRead(void);
|
int MultiRead(void);
|
||||||
|
|
||||||
@ -326,7 +334,7 @@ class S3fsMultiCurl
|
|||||||
|
|
||||||
S3fsMultiSuccessCallback SetSuccessCallback(S3fsMultiSuccessCallback function);
|
S3fsMultiSuccessCallback SetSuccessCallback(S3fsMultiSuccessCallback function);
|
||||||
S3fsMultiRetryCallback SetRetryCallback(S3fsMultiRetryCallback function);
|
S3fsMultiRetryCallback SetRetryCallback(S3fsMultiRetryCallback function);
|
||||||
bool Clear(void);
|
bool Clear(void) { return ClearEx(true); }
|
||||||
bool SetS3fsCurlObject(S3fsCurl* s3fscurl);
|
bool SetS3fsCurlObject(S3fsCurl* s3fscurl);
|
||||||
int Request(void);
|
int Request(void);
|
||||||
};
|
};
|
||||||
|
@ -202,7 +202,7 @@ void PageList::FreeList(fdpage_list_t& list)
|
|||||||
|
|
||||||
PageList::PageList(size_t size, bool is_init)
|
PageList::PageList(size_t size, bool is_init)
|
||||||
{
|
{
|
||||||
Init(0, false);
|
Init(size, is_init);
|
||||||
}
|
}
|
||||||
|
|
||||||
PageList::~PageList()
|
PageList::~PageList()
|
||||||
@ -417,7 +417,6 @@ bool PageList::Serialize(CacheFileStat& file, bool is_output)
|
|||||||
}
|
}
|
||||||
string oneline;
|
string oneline;
|
||||||
stringstream ssall(ptmp);
|
stringstream ssall(ptmp);
|
||||||
free(ptmp);
|
|
||||||
|
|
||||||
// init
|
// init
|
||||||
Clear();
|
Clear();
|
||||||
@ -425,6 +424,7 @@ bool PageList::Serialize(CacheFileStat& file, bool is_output)
|
|||||||
// load(size)
|
// load(size)
|
||||||
if(!getline(ssall, oneline, '\n')){
|
if(!getline(ssall, oneline, '\n')){
|
||||||
DPRN("failed to parse stats.");
|
DPRN("failed to parse stats.");
|
||||||
|
free(ptmp);
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
size_t total = static_cast<size_t>(atoi(oneline.c_str()));
|
size_t total = static_cast<size_t>(atoi(oneline.c_str()));
|
||||||
@ -455,6 +455,7 @@ bool PageList::Serialize(CacheFileStat& file, bool is_output)
|
|||||||
// add new area
|
// add new area
|
||||||
SetInit(offset, size, is_init);
|
SetInit(offset, size, is_init);
|
||||||
}
|
}
|
||||||
|
free(ptmp);
|
||||||
if(is_err){
|
if(is_err){
|
||||||
DPRN("failed to parse stats.");
|
DPRN("failed to parse stats.");
|
||||||
Clear();
|
Clear();
|
||||||
|
277
src/s3fs.cpp
277
src/s3fs.cpp
@ -111,17 +111,17 @@ static int check_parent_object_access(const char* path, int mask);
|
|||||||
static FdEntity* get_local_fent(const char* path, bool is_load = false);
|
static FdEntity* get_local_fent(const char* path, bool is_load = false);
|
||||||
static bool multi_head_callback(S3fsCurl* s3fscurl);
|
static bool multi_head_callback(S3fsCurl* s3fscurl);
|
||||||
static S3fsCurl* multi_head_retry_callback(S3fsCurl* s3fscurl);
|
static S3fsCurl* multi_head_retry_callback(S3fsCurl* s3fscurl);
|
||||||
static int readdir_multi_head(const char* path, S3ObjList& head);
|
static int readdir_multi_head(const char* path, S3ObjList& head, void* buf, fuse_fill_dir_t filler);
|
||||||
static int list_bucket(const char* path, S3ObjList& head, const char* delimiter);
|
static int list_bucket(const char* path, S3ObjList& head, const char* delimiter);
|
||||||
static int directory_empty(const char* path);
|
static int directory_empty(const char* path);
|
||||||
static bool is_truncated(const char* xml);
|
static bool is_truncated(xmlDocPtr doc);;
|
||||||
static int append_objects_from_xml_ex(const char* path, xmlDocPtr doc, xmlXPathContextPtr ctx,
|
static int append_objects_from_xml_ex(const char* path, xmlDocPtr doc, xmlXPathContextPtr ctx,
|
||||||
const char* ex_contents, const char* ex_key, const char* ex_etag, int isCPrefix, S3ObjList& head);
|
const char* ex_contents, const char* ex_key, const char* ex_etag, int isCPrefix, S3ObjList& head);
|
||||||
static int append_objects_from_xml(const char* path, const char* xml, S3ObjList& head);
|
static int append_objects_from_xml(const char* path, xmlDocPtr doc, S3ObjList& head);
|
||||||
static bool GetXmlNsUrl(xmlDocPtr doc, string& nsurl);
|
static bool GetXmlNsUrl(xmlDocPtr doc, string& nsurl);
|
||||||
static xmlChar* get_base_exp(const char* xml, const char* exp);
|
static xmlChar* get_base_exp(xmlDocPtr doc, const char* exp);
|
||||||
static xmlChar* get_prefix(const char* xml);
|
static xmlChar* get_prefix(xmlDocPtr doc);
|
||||||
static xmlChar* get_next_marker(const char* xml);
|
static xmlChar* get_next_marker(xmlDocPtr doc);
|
||||||
static char* get_object_name(xmlDocPtr doc, xmlNodePtr node, const char* path);
|
static char* get_object_name(xmlDocPtr doc, xmlNodePtr node, const char* path);
|
||||||
static int put_headers(const char* path, headers_t& meta, bool ow_sse_flg);
|
static int put_headers(const char* path, headers_t& meta, bool ow_sse_flg);
|
||||||
static int rename_large_object(const char* from, const char* to);
|
static int rename_large_object(const char* from, const char* to);
|
||||||
@ -194,6 +194,8 @@ static bool is_special_name_folder_object(const char* path)
|
|||||||
if(0 != s3fscurl.HeadRequest(strpath.c_str(), header)){
|
if(0 != s3fscurl.HeadRequest(strpath.c_str(), header)){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
header.clear();
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -693,6 +695,7 @@ static int s3fs_getattr(const char* path, struct stat* stbuf)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
FPRNINFO("[path=%s] uid=%u, gid=%u, mode=%04o", path, (unsigned int)(stbuf->st_uid), (unsigned int)(stbuf->st_gid), stbuf->st_mode);
|
FPRNINFO("[path=%s] uid=%u, gid=%u, mode=%04o", path, (unsigned int)(stbuf->st_uid), (unsigned int)(stbuf->st_gid), stbuf->st_mode);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -728,6 +731,7 @@ static int s3fs_readlink(const char* path, char* buf, size_t size)
|
|||||||
buf[ressize] = '\0';
|
buf[ressize] = '\0';
|
||||||
|
|
||||||
FdManager::get()->Close(ent);
|
FdManager::get()->Close(ent);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -765,6 +769,7 @@ static int s3fs_mknod(const char *path, mode_t mode, dev_t rdev)
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
StatCache::getStatCacheData()->DelStat(path);
|
StatCache::getStatCacheData()->DelStat(path);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -804,6 +809,7 @@ static int s3fs_create(const char* path, mode_t mode, struct fuse_file_info* fi)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
fi->fh = ent->GetFd();
|
fi->fh = ent->GetFd();
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -855,6 +861,8 @@ static int s3fs_mkdir(const char* path, mode_t mode)
|
|||||||
|
|
||||||
result = create_directory_object(path, mode, time(NULL), pcxt->uid, pcxt->gid);
|
result = create_directory_object(path, mode, time(NULL), pcxt->uid, pcxt->gid);
|
||||||
StatCache::getStatCacheData()->DelStat(path);
|
StatCache::getStatCacheData()->DelStat(path);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -871,6 +879,7 @@ static int s3fs_unlink(const char* path)
|
|||||||
result = s3fscurl.DeleteRequest(path);
|
result = s3fscurl.DeleteRequest(path);
|
||||||
FdManager::DeleteCacheFile(path);
|
FdManager::DeleteCacheFile(path);
|
||||||
StatCache::getStatCacheData()->DelStat(path);
|
StatCache::getStatCacheData()->DelStat(path);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -941,6 +950,8 @@ static int s3fs_rmdir(const char* path)
|
|||||||
strpath += "_$folder$";
|
strpath += "_$folder$";
|
||||||
result = s3fscurl.DeleteRequest(strpath.c_str());
|
result = s3fscurl.DeleteRequest(strpath.c_str());
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -991,6 +1002,7 @@ static int s3fs_symlink(const char* from, const char* to)
|
|||||||
FdManager::get()->Close(ent);
|
FdManager::get()->Close(ent);
|
||||||
|
|
||||||
StatCache::getStatCacheData()->DelStat(to);
|
StatCache::getStatCacheData()->DelStat(to);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1293,6 +1305,8 @@ static int s3fs_rename(const char* from, const char* to)
|
|||||||
result = rename_object_nocopy(from, to);
|
result = rename_object_nocopy(from, to);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1364,6 +1378,7 @@ static int s3fs_chmod(const char* path, mode_t mode)
|
|||||||
}
|
}
|
||||||
StatCache::getStatCacheData()->DelStat(nowcache);
|
StatCache::getStatCacheData()->DelStat(nowcache);
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1443,6 +1458,8 @@ static int s3fs_chmod_nocopy(const char* path, mode_t mode)
|
|||||||
|
|
||||||
StatCache::getStatCacheData()->DelStat(nowcache);
|
StatCache::getStatCacheData()->DelStat(nowcache);
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1523,6 +1540,7 @@ static int s3fs_chown(const char* path, uid_t uid, gid_t gid)
|
|||||||
}
|
}
|
||||||
StatCache::getStatCacheData()->DelStat(nowcache);
|
StatCache::getStatCacheData()->DelStat(nowcache);
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1612,6 +1630,8 @@ static int s3fs_chown_nocopy(const char* path, uid_t uid, gid_t gid)
|
|||||||
|
|
||||||
StatCache::getStatCacheData()->DelStat(nowcache);
|
StatCache::getStatCacheData()->DelStat(nowcache);
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1678,6 +1698,7 @@ static int s3fs_utimens(const char* path, const struct timespec ts[2])
|
|||||||
}
|
}
|
||||||
StatCache::getStatCacheData()->DelStat(nowcache);
|
StatCache::getStatCacheData()->DelStat(nowcache);
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1766,6 +1787,8 @@ static int s3fs_utimens_nocopy(const char* path, const struct timespec ts[2])
|
|||||||
|
|
||||||
StatCache::getStatCacheData()->DelStat(nowcache);
|
StatCache::getStatCacheData()->DelStat(nowcache);
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1814,6 +1837,7 @@ static int s3fs_truncate(const char* path, off_t size)
|
|||||||
FdManager::get()->Close(ent);
|
FdManager::get()->Close(ent);
|
||||||
|
|
||||||
StatCache::getStatCacheData()->DelStat(path);
|
StatCache::getStatCacheData()->DelStat(path);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -1852,6 +1876,7 @@ static int s3fs_open(const char* path, struct fuse_file_info* fi)
|
|||||||
return -EIO;
|
return -EIO;
|
||||||
}
|
}
|
||||||
fi->fh = ent->GetFd();
|
fi->fh = ent->GetFd();
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -1957,6 +1982,8 @@ static int s3fs_flush(const char* path, struct fuse_file_info* fi)
|
|||||||
result = ent->Flush(meta, true, false);
|
result = ent->Flush(meta, true, false);
|
||||||
FdManager::get()->Close(ent);
|
FdManager::get()->Close(ent);
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1990,6 +2017,8 @@ static int s3fs_release(const char* path, struct fuse_file_info* fi)
|
|||||||
DPRNNN("Warning - file(%s),fd(%d) is still opened.", path, ent->GetFd());
|
DPRNNN("Warning - file(%s),fd(%d) is still opened.", path, ent->GetFd());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2003,6 +2032,8 @@ static int s3fs_opendir(const char* path, struct fuse_file_info* fi)
|
|||||||
if(0 == (result = check_object_access(path, mask, NULL))){
|
if(0 == (result = check_object_access(path, mask, NULL))){
|
||||||
result = check_parent_object_access(path, mask);
|
result = check_parent_object_access(path, mask);
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2037,11 +2068,12 @@ static S3fsCurl* multi_head_retry_callback(S3fsCurl* s3fscurl)
|
|||||||
return newcurl;
|
return newcurl;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int readdir_multi_head(const char* path, S3ObjList& head)
|
static int readdir_multi_head(const char* path, S3ObjList& head, void* buf, fuse_fill_dir_t filler)
|
||||||
{
|
{
|
||||||
S3fsMultiCurl curlmulti;
|
S3fsMultiCurl curlmulti;
|
||||||
s3obj_list_t headlist;
|
s3obj_list_t headlist;
|
||||||
int result;
|
s3obj_list_t fillerlist;
|
||||||
|
int result = 0;
|
||||||
|
|
||||||
FPRNN("[path=%s][list=%zu]", path, headlist.size());
|
FPRNN("[path=%s][list=%zu]", path, headlist.size());
|
||||||
|
|
||||||
@ -2057,11 +2089,18 @@ static int readdir_multi_head(const char* path, S3ObjList& head)
|
|||||||
s3obj_list_t::iterator iter;
|
s3obj_list_t::iterator iter;
|
||||||
long cnt;
|
long cnt;
|
||||||
|
|
||||||
|
fillerlist.clear();
|
||||||
// Make single head request(with max).
|
// Make single head request(with max).
|
||||||
for(iter = headlist.begin(), cnt = 0; headlist.end() != iter && cnt < S3fsMultiCurl::GetMaxMultiRequest(); iter = headlist.erase(iter)){
|
for(iter = headlist.begin(), cnt = 0; headlist.end() != iter && cnt < S3fsMultiCurl::GetMaxMultiRequest(); iter = headlist.erase(iter)){
|
||||||
string disppath = path + (*iter);
|
string disppath = path + (*iter);
|
||||||
string etag = head.GetETag((*iter).c_str());
|
string etag = head.GetETag((*iter).c_str());
|
||||||
|
|
||||||
|
string fillpath = disppath;
|
||||||
|
if('/' == disppath[disppath.length() - 1]){
|
||||||
|
fillpath = fillpath.substr(0, fillpath.length() -1);
|
||||||
|
}
|
||||||
|
fillerlist.push_back(fillpath);
|
||||||
|
|
||||||
if(StatCache::getStatCacheData()->HasStat(disppath, etag.c_str())){
|
if(StatCache::getStatCacheData()->HasStat(disppath, etag.c_str())){
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -2087,6 +2126,20 @@ static int readdir_multi_head(const char* path, S3ObjList& head)
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// populate fuse buffer
|
||||||
|
// here is best posision, because a case is cache size < files in directory
|
||||||
|
//
|
||||||
|
for(iter = fillerlist.begin(); fillerlist.end() != iter; iter++){
|
||||||
|
struct stat st;
|
||||||
|
string bpath = mybasename((*iter));
|
||||||
|
if(StatCache::getStatCacheData()->GetStat((*iter), &st)){
|
||||||
|
filler(buf, bpath.c_str(), &st, 0);
|
||||||
|
}else{
|
||||||
|
FPRNNN("Could not find %s file in stat cache.", (*iter).c_str());
|
||||||
|
filler(buf, bpath.c_str(), 0, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// reinit for loop.
|
// reinit for loop.
|
||||||
curlmulti.Clear();
|
curlmulti.Clear();
|
||||||
}
|
}
|
||||||
@ -2118,21 +2171,16 @@ static int s3fs_readdir(const char* path, void* buf, fuse_fill_dir_t filler, off
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// populate fuse buffer
|
|
||||||
head.GetNameList(headlist);
|
|
||||||
s3obj_list_t::const_iterator liter;
|
|
||||||
for(liter = headlist.begin(); headlist.end() != liter; liter++){
|
|
||||||
filler(buf, (*liter).c_str(), 0, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send multi head request for stats caching.
|
// Send multi head request for stats caching.
|
||||||
string strpath = path;
|
string strpath = path;
|
||||||
if(strcmp(path, "/") != 0){
|
if(strcmp(path, "/") != 0){
|
||||||
strpath += "/";
|
strpath += "/";
|
||||||
}
|
}
|
||||||
if(0 != (result = readdir_multi_head(strpath.c_str(), head))){
|
if(0 != (result = readdir_multi_head(strpath.c_str(), head, buf, filler))){
|
||||||
DPRN("readdir_multi_head returns error(%d).", result);
|
DPRN("readdir_multi_head returns error(%d).", result);
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2144,6 +2192,7 @@ static int list_bucket(const char* path, S3ObjList& head, const char* delimiter)
|
|||||||
string next_marker = "";
|
string next_marker = "";
|
||||||
bool truncated = true;
|
bool truncated = true;
|
||||||
S3fsCurl s3fscurl;
|
S3fsCurl s3fscurl;
|
||||||
|
xmlDocPtr doc;
|
||||||
BodyData* body;
|
BodyData* body;
|
||||||
|
|
||||||
FPRNN("[path=%s]", path);
|
FPRNN("[path=%s]", path);
|
||||||
@ -2177,21 +2226,34 @@ static int list_bucket(const char* path, S3ObjList& head, const char* delimiter)
|
|||||||
}
|
}
|
||||||
body = s3fscurl.GetBodyData();
|
body = s3fscurl.GetBodyData();
|
||||||
|
|
||||||
if(0 != append_objects_from_xml(path, body->str(), head)){
|
// xmlDocPtr
|
||||||
DPRN("append_objects_from_xml returns with error.");
|
if(NULL == (doc = xmlReadMemory(body->str(), static_cast<int>(body->size()), "", NULL, 0))){
|
||||||
|
DPRN("xmlReadMemory returns with error.");
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
truncated = is_truncated(body->str());
|
if(0 != append_objects_from_xml(path, doc, head)){
|
||||||
if(truncated){
|
DPRN("append_objects_from_xml returns with error.");
|
||||||
xmlChar* tmpch = get_next_marker(body->str());
|
xmlFreeDoc(doc);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(true == (truncated = is_truncated(doc))){
|
||||||
|
xmlChar* tmpch = get_next_marker(doc);
|
||||||
if(tmpch){
|
if(tmpch){
|
||||||
next_marker = (char*)tmpch;
|
next_marker = (char*)tmpch;
|
||||||
xmlFree(tmpch);
|
xmlFree(tmpch);
|
||||||
|
}else{
|
||||||
|
DPRN("Could not find next marker, thus break loop.");
|
||||||
|
truncated = false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
xmlFreeDoc(doc);
|
||||||
|
S3FS_XMLFREEDOC(doc);
|
||||||
|
|
||||||
// reset(initialize) curl object
|
// reset(initialize) curl object
|
||||||
s3fscurl.DestroyCurlHandle();
|
s3fscurl.DestroyCurlHandle();
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2203,31 +2265,52 @@ static int append_objects_from_xml_ex(const char* path, xmlDocPtr doc, xmlXPathC
|
|||||||
xmlXPathObjectPtr contents_xp;
|
xmlXPathObjectPtr contents_xp;
|
||||||
xmlNodeSetPtr content_nodes;
|
xmlNodeSetPtr content_nodes;
|
||||||
|
|
||||||
contents_xp = xmlXPathEvalExpression((xmlChar*)ex_contents, ctx);
|
if(NULL == (contents_xp = xmlXPathEvalExpression((xmlChar*)ex_contents, ctx))){
|
||||||
|
DPRNNN("xmlXPathEvalExpression returns null.");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(xmlXPathNodeSetIsEmpty(contents_xp->nodesetval)){
|
||||||
|
DPRNNN("contents_xp->nodesetval is empty.");
|
||||||
|
S3FS_XMLXPATHFREEOBJECT(contents_xp);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
content_nodes = contents_xp->nodesetval;
|
content_nodes = contents_xp->nodesetval;
|
||||||
|
|
||||||
|
bool is_dir;
|
||||||
|
string stretag;
|
||||||
int i;
|
int i;
|
||||||
for(i = 0; i < content_nodes->nodeNr; i++){
|
for(i = 0; i < content_nodes->nodeNr; i++){
|
||||||
ctx->node = content_nodes->nodeTab[i];
|
ctx->node = content_nodes->nodeTab[i];
|
||||||
|
|
||||||
// object name
|
// object name
|
||||||
xmlXPathObjectPtr key = xmlXPathEvalExpression((xmlChar*)ex_key, ctx);
|
xmlXPathObjectPtr key;
|
||||||
|
if(NULL == (key = xmlXPathEvalExpression((xmlChar*)ex_key, ctx))){
|
||||||
|
DPRNNN("key is null. but continue.");
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if(xmlXPathNodeSetIsEmpty(key->nodesetval)){
|
||||||
|
DPRNNN("node is empty. but continue.");
|
||||||
|
xmlXPathFreeObject(key);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
xmlNodeSetPtr key_nodes = key->nodesetval;
|
xmlNodeSetPtr key_nodes = key->nodesetval;
|
||||||
char* name = get_object_name(doc, key_nodes->nodeTab[0]->xmlChildrenNode, path);
|
char* name = get_object_name(doc, key_nodes->nodeTab[0]->xmlChildrenNode, path);
|
||||||
|
|
||||||
if(!name){
|
if(!name){
|
||||||
DPRNNN("append_objects_from_xml_ex name is something wrong. but continue.");
|
DPRNNN("name is something wrong. but continue.");
|
||||||
|
|
||||||
}else if((const char*)name != c_strErrorObjectName){
|
}else if((const char*)name != c_strErrorObjectName){
|
||||||
bool is_dir = isCPrefix ? true : false;
|
is_dir = isCPrefix ? true : false;
|
||||||
string stretag = "";
|
stretag = "";
|
||||||
|
|
||||||
if(!isCPrefix && ex_etag){
|
if(!isCPrefix && ex_etag){
|
||||||
// Get ETag
|
// Get ETag
|
||||||
xmlXPathObjectPtr ETag = xmlXPathEvalExpression((xmlChar*)ex_etag, ctx);
|
xmlXPathObjectPtr ETag;
|
||||||
if(ETag){
|
if(NULL != (ETag = xmlXPathEvalExpression((xmlChar*)ex_etag, ctx))){
|
||||||
|
if(xmlXPathNodeSetIsEmpty(ETag->nodesetval)){
|
||||||
|
DPRNNN("ETag->nodesetval is empty.");
|
||||||
|
}else{
|
||||||
xmlNodeSetPtr etag_nodes = ETag->nodesetval;
|
xmlNodeSetPtr etag_nodes = ETag->nodesetval;
|
||||||
if(etag_nodes){
|
|
||||||
xmlChar* petag = xmlNodeListGetString(doc, etag_nodes->nodeTab[0]->xmlChildrenNode, 1);
|
xmlChar* petag = xmlNodeListGetString(doc, etag_nodes->nodeTab[0]->xmlChildrenNode, 1);
|
||||||
if(petag){
|
if(petag){
|
||||||
stretag = (char*)petag;
|
stretag = (char*)petag;
|
||||||
@ -2242,44 +2325,53 @@ static int append_objects_from_xml_ex(const char* path, xmlDocPtr doc, xmlXPathC
|
|||||||
xmlXPathFreeObject(key);
|
xmlXPathFreeObject(key);
|
||||||
xmlXPathFreeObject(contents_xp);
|
xmlXPathFreeObject(contents_xp);
|
||||||
free(name);
|
free(name);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
free(name);
|
free(name);
|
||||||
}else{
|
}else{
|
||||||
DPRNINFO("append_objects_from_xml_ex name is file or subdir in dir. but continue.");
|
DPRNINFO("name is file or subdir in dir. but continue.");
|
||||||
}
|
}
|
||||||
xmlXPathFreeObject(key);
|
xmlXPathFreeObject(key);
|
||||||
}
|
}
|
||||||
xmlXPathFreeObject(contents_xp);
|
S3FS_XMLXPATHFREEOBJECT(contents_xp);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool GetXmlNsUrl(xmlDocPtr doc, string& nsurl)
|
static bool GetXmlNsUrl(xmlDocPtr doc, string& nsurl)
|
||||||
{
|
{
|
||||||
|
static time_t tmLast = 0; // cache for 60 sec.
|
||||||
|
static string strNs("");
|
||||||
bool result = false;
|
bool result = false;
|
||||||
|
|
||||||
if(!doc){
|
if(!doc){
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
if((tmLast + 60) < time(NULL)){
|
||||||
|
// refresh
|
||||||
|
tmLast = time(NULL);
|
||||||
|
strNs = "";
|
||||||
xmlNodePtr pRootNode = xmlDocGetRootElement(doc);
|
xmlNodePtr pRootNode = xmlDocGetRootElement(doc);
|
||||||
if(pRootNode){
|
if(pRootNode){
|
||||||
xmlNsPtr* nslist = xmlGetNsList(doc, pRootNode);
|
xmlNsPtr* nslist = xmlGetNsList(doc, pRootNode);
|
||||||
if(nslist && nslist[0]){
|
if(nslist){
|
||||||
if(nslist[0]->href){
|
if(nslist[0] && nslist[0]->href){
|
||||||
nsurl = (const char*)(nslist[0]->href);
|
strNs = (const char*)(nslist[0]->href);
|
||||||
|
}
|
||||||
|
S3FS_XMLFREE(nslist);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(0 < strNs.size()){
|
||||||
|
nsurl = strNs;
|
||||||
result = true;
|
result = true;
|
||||||
}
|
}
|
||||||
xmlFree(nslist);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int append_objects_from_xml(const char* path, const char* xml, S3ObjList& head)
|
static int append_objects_from_xml(const char* path, xmlDocPtr doc, S3ObjList& head)
|
||||||
{
|
{
|
||||||
xmlDocPtr doc;
|
|
||||||
xmlXPathContextPtr ctx;
|
|
||||||
string xmlnsurl;
|
string xmlnsurl;
|
||||||
string ex_contents = "//";
|
string ex_contents = "//";
|
||||||
string ex_key = "";
|
string ex_key = "";
|
||||||
@ -2287,17 +2379,18 @@ static int append_objects_from_xml(const char* path, const char* xml, S3ObjList&
|
|||||||
string ex_prefix = "";
|
string ex_prefix = "";
|
||||||
string ex_etag = "";
|
string ex_etag = "";
|
||||||
|
|
||||||
// If there is not <Prefix>, use path instead of it.
|
if(!doc){
|
||||||
xmlChar* pprefix = get_prefix(xml);
|
|
||||||
string prefix = (pprefix ? (char*)pprefix : path ? path : "");
|
|
||||||
xmlFree(pprefix);
|
|
||||||
|
|
||||||
doc = xmlReadMemory(xml, strlen(xml), "", NULL, 0);
|
|
||||||
if(doc == NULL){
|
|
||||||
DPRN("xmlReadMemory returns with error.");
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
ctx = xmlXPathNewContext(doc);
|
|
||||||
|
// If there is not <Prefix>, use path instead of it.
|
||||||
|
xmlChar* pprefix = get_prefix(doc);
|
||||||
|
string prefix = (pprefix ? (char*)pprefix : path ? path : "");
|
||||||
|
if(pprefix){
|
||||||
|
xmlFree(pprefix);
|
||||||
|
}
|
||||||
|
|
||||||
|
xmlXPathContextPtr ctx = xmlXPathNewContext(doc);
|
||||||
|
|
||||||
if(!noxmlns && GetXmlNsUrl(doc, xmlnsurl)){
|
if(!noxmlns && GetXmlNsUrl(doc, xmlnsurl)){
|
||||||
xmlXPathRegisterNs(ctx, (xmlChar*)"s3", (xmlChar*)xmlnsurl.c_str());
|
xmlXPathRegisterNs(ctx, (xmlChar*)"s3", (xmlChar*)xmlnsurl.c_str());
|
||||||
@ -2317,28 +2410,24 @@ static int append_objects_from_xml(const char* path, const char* xml, S3ObjList&
|
|||||||
-1 == append_objects_from_xml_ex(prefix.c_str(), doc, ctx, ex_cprefix.c_str(), ex_prefix.c_str(), NULL, 1, head) )
|
-1 == append_objects_from_xml_ex(prefix.c_str(), doc, ctx, ex_cprefix.c_str(), ex_prefix.c_str(), NULL, 1, head) )
|
||||||
{
|
{
|
||||||
DPRN("append_objects_from_xml_ex returns with error.");
|
DPRN("append_objects_from_xml_ex returns with error.");
|
||||||
xmlXPathFreeContext(ctx);
|
S3FS_XMLXPATHFREECONTEXT(ctx);
|
||||||
xmlFreeDoc(doc);
|
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
xmlXPathFreeContext(ctx);
|
S3FS_XMLXPATHFREECONTEXT(ctx);
|
||||||
xmlFreeDoc(doc);
|
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static xmlChar* get_base_exp(const char* xml, const char* exp)
|
static xmlChar* get_base_exp(xmlDocPtr doc, const char* exp)
|
||||||
{
|
{
|
||||||
xmlDocPtr doc;
|
|
||||||
xmlXPathContextPtr ctx;
|
|
||||||
xmlXPathObjectPtr marker_xp;
|
xmlXPathObjectPtr marker_xp;
|
||||||
xmlNodeSetPtr nodes;
|
|
||||||
xmlChar* result;
|
|
||||||
string xmlnsurl;
|
string xmlnsurl;
|
||||||
string exp_string = "//";
|
string exp_string = "//";
|
||||||
|
|
||||||
doc = xmlReadMemory(xml, strlen(xml), "", NULL, 0);
|
if(!doc){
|
||||||
ctx = xmlXPathNewContext(doc);
|
return NULL;
|
||||||
|
}
|
||||||
|
xmlXPathContextPtr ctx = xmlXPathNewContext(doc);
|
||||||
|
|
||||||
if(!noxmlns && GetXmlNsUrl(doc, xmlnsurl)){
|
if(!noxmlns && GetXmlNsUrl(doc, xmlnsurl)){
|
||||||
xmlXPathRegisterNs(ctx, (xmlChar*)"s3", (xmlChar*)xmlnsurl.c_str());
|
xmlXPathRegisterNs(ctx, (xmlChar*)"s3", (xmlChar*)xmlnsurl.c_str());
|
||||||
@ -2346,37 +2435,48 @@ static xmlChar* get_base_exp(const char* xml, const char* exp)
|
|||||||
}
|
}
|
||||||
exp_string += exp;
|
exp_string += exp;
|
||||||
|
|
||||||
marker_xp = xmlXPathEvalExpression((xmlChar *)exp_string.c_str(), ctx);
|
if(NULL == (marker_xp = xmlXPathEvalExpression((xmlChar *)exp_string.c_str(), ctx))){
|
||||||
nodes = marker_xp->nodesetval;
|
xmlXPathFreeContext(ctx);
|
||||||
|
|
||||||
if(nodes->nodeNr < 1)
|
|
||||||
return NULL;
|
return NULL;
|
||||||
|
}
|
||||||
result = xmlNodeListGetString(doc, nodes->nodeTab[0]->xmlChildrenNode, 1);
|
if(xmlXPathNodeSetIsEmpty(marker_xp->nodesetval)){
|
||||||
|
DPRNNN("marker_xp->nodesetval is empty.");
|
||||||
|
xmlXPathFreeObject(marker_xp);
|
||||||
|
xmlXPathFreeContext(ctx);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
xmlNodeSetPtr nodes = marker_xp->nodesetval;
|
||||||
|
xmlChar* result = xmlNodeListGetString(doc, nodes->nodeTab[0]->xmlChildrenNode, 1);
|
||||||
|
|
||||||
xmlXPathFreeObject(marker_xp);
|
xmlXPathFreeObject(marker_xp);
|
||||||
xmlXPathFreeContext(ctx);
|
xmlXPathFreeContext(ctx);
|
||||||
xmlFreeDoc(doc);
|
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static xmlChar* get_prefix(const char* xml)
|
static xmlChar* get_prefix(xmlDocPtr doc)
|
||||||
{
|
{
|
||||||
return get_base_exp(xml, "Prefix");
|
return get_base_exp(doc, "Prefix");
|
||||||
}
|
}
|
||||||
|
|
||||||
static xmlChar* get_next_marker(const char* xml)
|
static xmlChar* get_next_marker(xmlDocPtr doc)
|
||||||
{
|
{
|
||||||
return get_base_exp(xml, "NextMarker");
|
return get_base_exp(doc, "NextMarker");
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool is_truncated(const char* xml)
|
static bool is_truncated(xmlDocPtr doc)
|
||||||
{
|
{
|
||||||
if(strstr(xml, "<IsTruncated>true</IsTruncated>")){
|
bool result = false;
|
||||||
return true;
|
|
||||||
|
xmlChar* strTruncate = get_base_exp(doc, "IsTruncated");
|
||||||
|
if(!strTruncate){
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
return false;
|
if(0 == strcasecmp((const char*)strTruncate, "true")){
|
||||||
|
result = true;
|
||||||
|
}
|
||||||
|
xmlFree(strTruncate);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// return: the pointer to object name on allocated memory.
|
// return: the pointer to object name on allocated memory.
|
||||||
@ -2398,8 +2498,8 @@ static char* get_object_name(xmlDocPtr doc, xmlNodePtr node, const char* path)
|
|||||||
|
|
||||||
// Make dir path and filename
|
// Make dir path and filename
|
||||||
string strfullpath= (char*)fullpath;
|
string strfullpath= (char*)fullpath;
|
||||||
string strdirpath = mydirname((char*)fullpath);
|
string strdirpath = mydirname(string((char*)fullpath));
|
||||||
string strmybpath = mybasename((char*)fullpath);
|
string strmybpath = mybasename(string((char*)fullpath));
|
||||||
const char* dirpath = strdirpath.c_str();
|
const char* dirpath = strdirpath.c_str();
|
||||||
const char* mybname = strmybpath.c_str();
|
const char* mybname = strmybpath.c_str();
|
||||||
const char* basepath= (!path || '\0' == path[0] || '/' != path[0] ? path : &path[1]);
|
const char* basepath= (!path || '\0' == path[0] || '/' != path[0] ? path : &path[1]);
|
||||||
@ -2519,7 +2619,9 @@ static int s3fs_access(const char* path, int mask)
|
|||||||
((mask & X_OK) == X_OK) ? "X_OK " : "",
|
((mask & X_OK) == X_OK) ? "X_OK " : "",
|
||||||
(mask == F_OK) ? "F_OK" : "");
|
(mask == F_OK) ? "F_OK" : "");
|
||||||
|
|
||||||
return check_object_access(path, mask, NULL);
|
int result = check_object_access(path, mask, NULL);
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
static int s3fs_utility_mode(void)
|
static int s3fs_utility_mode(void)
|
||||||
@ -2590,6 +2692,8 @@ static int s3fs_check_service(void)
|
|||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
return EXIT_SUCCESS;
|
return EXIT_SUCCESS;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -3196,6 +3300,10 @@ static int my_fuse_opt_proc(void* data, const char* arg, int key, struct fuse_ar
|
|||||||
S3fsCurl::SetDnsCache(false);
|
S3fsCurl::SetDnsCache(false);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
if(0 == strcmp(arg, "nosscache")){
|
||||||
|
S3fsCurl::SetSslSessionCache(false);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
if(0 == STR2NCMP(arg, "parallel_count=") || 0 == STR2NCMP(arg, "parallel_upload=")){
|
if(0 == STR2NCMP(arg, "parallel_count=") || 0 == STR2NCMP(arg, "parallel_upload=")){
|
||||||
int maxpara = (int)strtoul(strchr(arg, '=') + sizeof(char), 0, 10);
|
int maxpara = (int)strtoul(strchr(arg, '=') + sizeof(char), 0, 10);
|
||||||
if(0 >= maxpara){
|
if(0 >= maxpara){
|
||||||
@ -3315,6 +3423,10 @@ int main(int argc, char* argv[])
|
|||||||
{0, 0, 0, 0}
|
{0, 0, 0, 0}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// init xml2
|
||||||
|
xmlInitParser();
|
||||||
|
LIBXML_TEST_VERSION
|
||||||
|
|
||||||
// get progam name - emulate basename
|
// get progam name - emulate basename
|
||||||
size_t found = string::npos;
|
size_t found = string::npos;
|
||||||
program_name.assign(argv[0]);
|
program_name.assign(argv[0]);
|
||||||
@ -3483,10 +3595,19 @@ int main(int argc, char* argv[])
|
|||||||
s3fs_oper.access = s3fs_access;
|
s3fs_oper.access = s3fs_access;
|
||||||
s3fs_oper.create = s3fs_create;
|
s3fs_oper.create = s3fs_create;
|
||||||
|
|
||||||
|
// init NSS
|
||||||
|
S3FS_INIT_NSS();
|
||||||
|
|
||||||
// now passing things off to fuse, fuse will finish evaluating the command line args
|
// now passing things off to fuse, fuse will finish evaluating the command line args
|
||||||
fuse_res = fuse_main(custom_args.argc, custom_args.argv, &s3fs_oper, NULL);
|
fuse_res = fuse_main(custom_args.argc, custom_args.argv, &s3fs_oper, NULL);
|
||||||
fuse_opt_free_args(&custom_args);
|
fuse_opt_free_args(&custom_args);
|
||||||
|
|
||||||
|
// cleanup NSS
|
||||||
|
S3FS_CLEANUP_NSS();
|
||||||
|
// cleanup xml2
|
||||||
|
xmlCleanupParser();
|
||||||
|
S3FS_MALLOCTRIM(0);
|
||||||
|
|
||||||
exit(fuse_res);
|
exit(fuse_res);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
84
src/s3fs.h
84
src/s3fs.h
@ -13,4 +13,88 @@
|
|||||||
} \
|
} \
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// s3fs use many small allocated chunk in heap area for
|
||||||
|
// stats cache and parsing xml, etc. The OS may decide
|
||||||
|
// that giving this little memory back to the kernel
|
||||||
|
// will cause too much overhead and delay the operation.
|
||||||
|
// So s3fs calls malloc_trim function to really get the
|
||||||
|
// memory back. Following macros is prepared for that
|
||||||
|
// your system does not have it.
|
||||||
|
//
|
||||||
|
// Address of gratitude, this workaround quotes a document
|
||||||
|
// of libxml2.
|
||||||
|
// http://xmlsoft.org/xmlmem.html
|
||||||
|
//
|
||||||
|
#ifdef HAVE_MALLOC_TRIM
|
||||||
|
|
||||||
|
#include <malloc.h>
|
||||||
|
|
||||||
|
#define DISPWARN_MALLOCTRIM(str)
|
||||||
|
#define S3FS_MALLOCTRIM(pad) malloc_trim(pad)
|
||||||
|
#define S3FS_XMLFREEDOC(doc) \
|
||||||
|
{ \
|
||||||
|
xmlFreeDoc(doc); \
|
||||||
|
S3FS_MALLOCTRIM(0); \
|
||||||
|
}
|
||||||
|
#define S3FS_XMLFREE(ptr) \
|
||||||
|
{ \
|
||||||
|
xmlFree(ptr); \
|
||||||
|
S3FS_MALLOCTRIM(0); \
|
||||||
|
}
|
||||||
|
#define S3FS_XMLXPATHFREECONTEXT(ctx) \
|
||||||
|
{ \
|
||||||
|
xmlXPathFreeContext(ctx); \
|
||||||
|
S3FS_MALLOCTRIM(0); \
|
||||||
|
}
|
||||||
|
#define S3FS_XMLXPATHFREEOBJECT(obj) \
|
||||||
|
{ \
|
||||||
|
xmlXPathFreeObject(obj); \
|
||||||
|
S3FS_MALLOCTRIM(0); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // HAVE_MALLOC_TRIM
|
||||||
|
|
||||||
|
#define DISPWARN_MALLOCTRIM(str) \
|
||||||
|
fprintf(stderr, "Warning: %s without malloc_trim is possibility of the use memory increase.\n", program_name.c_str())
|
||||||
|
#define S3FS_MALLOCTRIM(pad)
|
||||||
|
#define S3FS_XMLFREEDOC(doc) xmlFreeDoc(doc)
|
||||||
|
#define S3FS_XMLFREE(ptr) xmlFree(ptr)
|
||||||
|
#define S3FS_XMLXPATHFREECONTEXT(ctx) xmlXPathFreeContext(ctx)
|
||||||
|
#define S3FS_XMLXPATHFREEOBJECT(obj) xmlXPathFreeObject(obj)
|
||||||
|
|
||||||
|
#endif // HAVE_MALLOC_TRIM
|
||||||
|
|
||||||
|
//
|
||||||
|
// For initializing libcurl with NSS
|
||||||
|
// Normally libcurl initializes the NSS library, but usually allows
|
||||||
|
// you to initialize s3fs forcibly. Because Memory leak is reported
|
||||||
|
// in valgrind(about curl_global_init() function), and this is for
|
||||||
|
// the cancellation. When "--enable-nss-init" option is specified
|
||||||
|
// at configurarion, it makes NSS_INIT_ENABLED flag into Makefile.
|
||||||
|
// NOTICE
|
||||||
|
// This defines and macros is temporary, and this should be deleted.
|
||||||
|
//
|
||||||
|
#ifdef NSS_INIT_ENABLED
|
||||||
|
#include <nss.h>
|
||||||
|
#include <prinit.h>
|
||||||
|
|
||||||
|
#define S3FS_INIT_NSS() \
|
||||||
|
{ \
|
||||||
|
NSS_NoDB_Init(NULL); \
|
||||||
|
}
|
||||||
|
#define S3FS_CLEANUP_NSS() \
|
||||||
|
{ \
|
||||||
|
NSS_Shutdown(); \
|
||||||
|
PL_ArenaFinish(); \
|
||||||
|
PR_Cleanup(); \
|
||||||
|
}
|
||||||
|
|
||||||
|
#else // NSS_INIT_ENABLED
|
||||||
|
|
||||||
|
#define S3FS_INIT_NSS()
|
||||||
|
#define S3FS_CLEANUP_NSS()
|
||||||
|
|
||||||
|
#endif // NSS_INIT_ENABLED
|
||||||
|
|
||||||
#endif // S3FS_S3_H_
|
#endif // S3FS_S3_H_
|
||||||
|
@ -456,15 +456,40 @@ bool AutoLock::Unlock(void)
|
|||||||
// get user name from uid
|
// get user name from uid
|
||||||
string get_username(uid_t uid)
|
string get_username(uid_t uid)
|
||||||
{
|
{
|
||||||
struct passwd* ppw;
|
static size_t maxlen = 0; // set onece
|
||||||
if(NULL == (ppw = getpwuid(uid)) || NULL == ppw->pw_name){
|
int result;
|
||||||
DPRNNN("could not get username(errno=%d).", (int)errno);
|
char* pbuf;
|
||||||
|
struct passwd pwinfo;
|
||||||
|
struct passwd* ppwinfo = NULL;
|
||||||
|
|
||||||
|
// make buffer
|
||||||
|
if(0 == maxlen){
|
||||||
|
if(0 > (maxlen = (size_t)sysconf(_SC_GETPW_R_SIZE_MAX))){
|
||||||
|
DPRNNN("could not get max pw length.");
|
||||||
|
maxlen = 0;
|
||||||
return string("");
|
return string("");
|
||||||
}
|
}
|
||||||
return string(ppw->pw_name);
|
}
|
||||||
|
if(NULL == (pbuf = (char*)malloc(sizeof(char) * maxlen))){
|
||||||
|
DPRNCRIT("failed to allocate memory.");
|
||||||
|
return string("");
|
||||||
|
}
|
||||||
|
// get group infomation
|
||||||
|
if(0 != (result = getpwuid_r(uid, &pwinfo, pbuf, maxlen, &ppwinfo))){
|
||||||
|
DPRNNN("could not get pw infomation.");
|
||||||
|
free(pbuf);
|
||||||
|
return string("");
|
||||||
|
}
|
||||||
|
// check pw
|
||||||
|
if(NULL == ppwinfo){
|
||||||
|
free(pbuf);
|
||||||
|
return string("");
|
||||||
|
}
|
||||||
|
string name = SAFESTRPTR(ppwinfo->pw_name);
|
||||||
|
free(pbuf);
|
||||||
|
return name;
|
||||||
}
|
}
|
||||||
|
|
||||||
// check uid in group(gid)
|
|
||||||
int is_uid_inculde_group(uid_t uid, gid_t gid)
|
int is_uid_inculde_group(uid_t uid, gid_t gid)
|
||||||
{
|
{
|
||||||
static size_t maxlen = 0; // set onece
|
static size_t maxlen = 0; // set onece
|
||||||
@ -520,14 +545,14 @@ int is_uid_inculde_group(uid_t uid, gid_t gid)
|
|||||||
// dirname clobbers path so let it operate on a tmp copy
|
// dirname clobbers path so let it operate on a tmp copy
|
||||||
string mydirname(string path)
|
string mydirname(string path)
|
||||||
{
|
{
|
||||||
return string(dirname(&path[0]));
|
return string(dirname((char*)path.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// safe variant of basename
|
// safe variant of basename
|
||||||
// basename clobbers path so let it operate on a tmp copy
|
// basename clobbers path so let it operate on a tmp copy
|
||||||
string mybasename(string path)
|
string mybasename(string path)
|
||||||
{
|
{
|
||||||
return string(basename(&path[0]));
|
return string(basename((char*)path.c_str()));
|
||||||
}
|
}
|
||||||
|
|
||||||
// mkdir --parents
|
// mkdir --parents
|
||||||
@ -871,7 +896,11 @@ void show_help (void)
|
|||||||
" nodnscache (disable dns cache)\n"
|
" nodnscache (disable dns cache)\n"
|
||||||
" - s3fs is always using dns cache, this option make dns cache disable.\n"
|
" - s3fs is always using dns cache, this option make dns cache disable.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" multireq_max (default=\"500\")\n"
|
" nosscache (disable ssl session cache)\n"
|
||||||
|
" - s3fs is always using ssl session cache, this option make ssl \n"
|
||||||
|
" session cache disable.\n"
|
||||||
|
"\n"
|
||||||
|
" multireq_max (default=\"20\")\n"
|
||||||
" - maximum number of parallel request for listing objects.\n"
|
" - maximum number of parallel request for listing objects.\n"
|
||||||
"\n"
|
"\n"
|
||||||
" parallel_count (default=\"5\")\n"
|
" parallel_count (default=\"5\")\n"
|
||||||
|
Loading…
x
Reference in New Issue
Block a user