mirror of
https://github.com/s3fs-fuse/s3fs-fuse.git
synced 2024-12-23 01:08:54 +00:00
Summary of Changes(1.65 -> 1.66)
========================== List of Changes ========================== 1) Fixes bugs Fixes Issue 321: "no write permission for non-root user". (http://code.google.com/p/s3fs/issues/detail?id=321) Fixes a bug which s3fs does not set uid/gid headers when making symlink. 2) Cleanup code. Adds a common function which converts the Last-Modified header to utime. Deletes the useless cord and arranged it. 3) xmlns Changes that s3fs can decide using the xmlns url automatically. Then the noxmlns option is not needed anymore, but it is left. 4) Changes cache for performance Changes stat cache, it accumulates stat information and some headers. By adding some headers into cache, s3fs does not need to call curl_get_headers function. After changing, one cache entry increases in about 500 bytes from about 144 byte. Adds one condition to get out of the cache, that condition is by looking object's ETag. It works good for noticing changes about obojects. git-svn-id: http://s3fs.googlecode.com/svn/trunk@400 df820570-a93a-0410-bd06-b72b767a4274
This commit is contained in:
parent
a35cdc73b7
commit
8bd1483374
@ -1,7 +1,7 @@
|
||||
dnl Process this file with autoconf to produce a configure script.
|
||||
|
||||
AC_PREREQ(2.59)
|
||||
AC_INIT(s3fs, 1.65)
|
||||
AC_INIT(s3fs, 1.66)
|
||||
|
||||
|
||||
AC_CANONICAL_SYSTEM
|
||||
|
@ -87,6 +87,7 @@ sets the url to use to access Amazon S3. If you want to use HTTPS, then you can
|
||||
.TP
|
||||
\fB\-o\fR noxmlns - disable registing xml name space.
|
||||
disable registing xml name space for response of ListBucketResult and ListVersionsResult etc. Default name space is looked up from "http://s3.amazonaws.com/doc/2006-03-01".
|
||||
This option should not be specified now, because s3fs looks up xmlns automatically after v1.66.
|
||||
.TP
|
||||
\fB\-o\fR nocopyapi - for other incomplete compatibility object storage.
|
||||
For a distributed object storage which is compatibility S3 API without PUT(copy api).
|
||||
|
329
src/cache.cpp
329
src/cache.cpp
@ -24,141 +24,324 @@
|
||||
#include <unistd.h>
|
||||
#include <pthread.h>
|
||||
#include <string.h>
|
||||
#include <iostream>
|
||||
#include <assert.h>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <algorithm>
|
||||
|
||||
#include "common.h"
|
||||
#include "cache.h"
|
||||
#include "s3fs_util.h"
|
||||
|
||||
using namespace std;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Typedef
|
||||
// Static
|
||||
//-------------------------------------------------------------------
|
||||
typedef std::map<std::string, struct stat_cache_entry> stat_cache_t; // key=path
|
||||
StatCache StatCache::singleton;
|
||||
pthread_mutex_t StatCache::stat_cache_lock;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Static valiables
|
||||
// Constructor/Destructor
|
||||
//-------------------------------------------------------------------
|
||||
static stat_cache_t stat_cache;
|
||||
static pthread_mutex_t stat_cache_lock;
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Functions
|
||||
//-------------------------------------------------------------------
|
||||
int init_stat_cache_mutex(void)
|
||||
StatCache::StatCache()
|
||||
{
|
||||
return pthread_mutex_init(&stat_cache_lock, NULL);
|
||||
if(this == StatCache::getStatCacheData()){
|
||||
pthread_mutex_init(&(StatCache::stat_cache_lock), NULL);
|
||||
}else{
|
||||
assert(false);
|
||||
}
|
||||
CacheSize = 1000;
|
||||
ExpireTime = 0;
|
||||
IsExpireTime = false;
|
||||
}
|
||||
|
||||
int destroy_stat_cache_mutex(void)
|
||||
StatCache::~StatCache()
|
||||
{
|
||||
return pthread_mutex_destroy(&stat_cache_lock);
|
||||
if(this == StatCache::getStatCacheData()){
|
||||
pthread_mutex_destroy(&(StatCache::stat_cache_lock));
|
||||
}else{
|
||||
assert(false);
|
||||
}
|
||||
}
|
||||
|
||||
int get_stat_cache_entry(const char *path, struct stat *buf)
|
||||
//-------------------------------------------------------------------
|
||||
// Methods
|
||||
//-------------------------------------------------------------------
|
||||
unsigned long StatCache::GetCacheSize(void) const
|
||||
{
|
||||
int is_delete_cache = 0;
|
||||
string strpath = path;
|
||||
return CacheSize;
|
||||
}
|
||||
|
||||
pthread_mutex_lock(&stat_cache_lock);
|
||||
unsigned long StatCache::SetCacheSize(unsigned long size)
|
||||
{
|
||||
unsigned long old = CacheSize;
|
||||
CacheSize = size;
|
||||
return old;
|
||||
}
|
||||
|
||||
time_t StatCache::GetExpireTime(void) const
|
||||
{
|
||||
return (IsExpireTime ? ExpireTime : (-1));
|
||||
}
|
||||
|
||||
time_t StatCache::SetExpireTime(time_t expire)
|
||||
{
|
||||
time_t old = ExpireTime;
|
||||
ExpireTime = expire;
|
||||
IsExpireTime = true;
|
||||
return old;
|
||||
}
|
||||
|
||||
time_t StatCache::UnsetExpireTime(void)
|
||||
{
|
||||
time_t old = IsExpireTime ? ExpireTime : (-1);
|
||||
ExpireTime = 0;
|
||||
IsExpireTime = false;
|
||||
return old;
|
||||
}
|
||||
|
||||
bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag)
|
||||
{
|
||||
bool is_delete_cache = false;
|
||||
string strpath = key;
|
||||
|
||||
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||
|
||||
stat_cache_t::iterator iter = stat_cache.end();
|
||||
if('/' != strpath[strpath.length() - 1]){
|
||||
if(overcheck && '/' != strpath[strpath.length() - 1]){
|
||||
strpath += "/";
|
||||
iter = stat_cache.find(strpath.c_str());
|
||||
}
|
||||
if(iter == stat_cache.end()){
|
||||
strpath = path;
|
||||
strpath = key;
|
||||
iter = stat_cache.find(strpath.c_str());
|
||||
}
|
||||
|
||||
if(iter != stat_cache.end()) {
|
||||
if(!is_stat_cache_expire_time || ((*iter).second.cache_date + stat_cache_expire_time) >= time(NULL)){
|
||||
// hit
|
||||
FGPRINT(" stat cache hit [path=%s] [time=%ld] [hit count=%lu]\n",
|
||||
strpath.c_str(), (*iter).second.cache_date, (*iter).second.hit_count);
|
||||
|
||||
if(buf != NULL){
|
||||
*buf = (*iter).second.stbuf;
|
||||
if(!IsExpireTime|| ((*iter).second.cache_date + ExpireTime) >= time(NULL)){
|
||||
// hit without checking etag
|
||||
if(petag){
|
||||
string stretag = (*iter).second.meta["ETag"];
|
||||
if('\0' != petag[0] && 0 != strcmp(petag, stretag.c_str())){
|
||||
is_delete_cache = true;
|
||||
}
|
||||
}
|
||||
(*iter).second.hit_count++;
|
||||
pthread_mutex_unlock(&stat_cache_lock);
|
||||
return 0;
|
||||
if(is_delete_cache){
|
||||
// not hit by different ETag
|
||||
FGPRINT(" stat cache not hit by ETag[path=%s][time=%ld][hit count=%lu][ETag(%s)!=(%s)]\n",
|
||||
strpath.c_str(), (*iter).second.cache_date, (*iter).second.hit_count,
|
||||
petag ? petag : "null", (*iter).second.meta["ETag"].c_str());
|
||||
}else{
|
||||
// hit
|
||||
FGPRINT(" stat cache hit [path=%s] [time=%ld] [hit count=%lu]\n",
|
||||
strpath.c_str(), (*iter).second.cache_date, (*iter).second.hit_count);
|
||||
|
||||
if(pst!= NULL){
|
||||
*pst= (*iter).second.stbuf;
|
||||
}
|
||||
if(meta != NULL){
|
||||
meta->clear();
|
||||
(*meta) = (*iter).second.meta;
|
||||
}
|
||||
|
||||
(*iter).second.hit_count++;
|
||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||
return true;
|
||||
}
|
||||
|
||||
}else{
|
||||
// timeout
|
||||
is_delete_cache = 1;
|
||||
is_delete_cache = true;
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&stat_cache_lock);
|
||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||
|
||||
if(is_delete_cache){
|
||||
delete_stat_cache_entry(strpath.c_str());
|
||||
DelStat(strpath);
|
||||
}
|
||||
|
||||
return -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
void add_stat_cache_entry(const char *path, struct stat *st)
|
||||
bool StatCache::AddStat(std::string& key, headers_t& meta)
|
||||
{
|
||||
FGPRINT(" add_stat_cache_entry[path=%s]\n", path);
|
||||
if(CacheSize< 1){
|
||||
return true;
|
||||
}
|
||||
FGPRINT(" add_stat_cache_entry[path=%s]\n", key.c_str());
|
||||
|
||||
if(max_stat_cache_size < 1){
|
||||
return;
|
||||
if(stat_cache.size() > CacheSize){
|
||||
if(!TruncateCache()){
|
||||
return false;
|
||||
}
|
||||
}
|
||||
if(stat_cache.size() > max_stat_cache_size){
|
||||
truncate_stat_cache();
|
||||
|
||||
struct stat st;
|
||||
if(!convert_header_to_stat(key.c_str(), meta, &st)){
|
||||
return false;
|
||||
}
|
||||
pthread_mutex_lock(&stat_cache_lock);
|
||||
stat_cache[path].stbuf = *st;
|
||||
stat_cache[path].cache_date = time(NULL); // Set time.
|
||||
pthread_mutex_unlock(&stat_cache_lock);
|
||||
|
||||
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||
stat_cache[key].stbuf = st;
|
||||
stat_cache[key].hit_count = 0;
|
||||
stat_cache[key].cache_date = time(NULL); // Set time.
|
||||
|
||||
//copy only some keys
|
||||
for (headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter) {
|
||||
string tag = (*iter).first;
|
||||
string value = (*iter).second;
|
||||
if(tag == "Content-Type"){
|
||||
stat_cache[key].meta[tag] = value;
|
||||
}else if(tag == "Content-Length"){
|
||||
stat_cache[key].meta[tag] = value;
|
||||
}else if(tag == "ETag"){
|
||||
stat_cache[key].meta[tag] = value;
|
||||
}else if(tag == "Last-Modified"){
|
||||
stat_cache[key].meta[tag] = value;
|
||||
}else if(tag.substr(0, 5) == "x-amz"){
|
||||
stat_cache[key].meta[tag] = value;
|
||||
}else{
|
||||
// Check for upper case
|
||||
transform(tag.begin(), tag.end(), tag.begin(), static_cast<int (*)(int)>(std::tolower));
|
||||
if(tag.substr(0, 5) == "x-amz"){
|
||||
stat_cache[key].meta[tag] = value;
|
||||
}
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void delete_stat_cache_entry(const char *path)
|
||||
bool StatCache::TruncateCache(void)
|
||||
{
|
||||
FGPRINT(" delete_stat_cache_entry[path=%s]\n", path);
|
||||
string path_to_delete;
|
||||
unsigned int lowest_hit_count = 0;
|
||||
|
||||
pthread_mutex_lock(&stat_cache_lock);
|
||||
stat_cache_t::iterator iter = stat_cache.find(path);
|
||||
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);
|
||||
|
||||
FGPRINT(" truncate_stat_cache_entry[path=%s]\n", path_to_delete.c_str());
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool StatCache::DelStat(const char* key)
|
||||
{
|
||||
if(!key){
|
||||
return false;
|
||||
}
|
||||
FGPRINT(" delete_stat_cache_entry[path=%s]\n", key);
|
||||
|
||||
pthread_mutex_lock(&StatCache::stat_cache_lock);
|
||||
stat_cache_t::iterator iter = stat_cache.find(key);
|
||||
if(iter != stat_cache.end()){
|
||||
stat_cache.erase(iter);
|
||||
}
|
||||
if(0 < strlen(path) && '/' != path[strlen(path) - 1]){
|
||||
// If there is "path/" cache, delete it.
|
||||
string strpath = path;
|
||||
strpath += "/";
|
||||
if(0 < strlen(key) && 0 != strcmp(key, "/")){
|
||||
string strpath = key;
|
||||
if('/' == strpath[strpath.length() - 1]){
|
||||
// If there is "path" cache, delete it.
|
||||
strpath = strpath.substr(0, strpath.length() - 1);
|
||||
}else{
|
||||
// If there is "path/" cache, delete it.
|
||||
strpath += "/";
|
||||
}
|
||||
iter = stat_cache.find(strpath.c_str());
|
||||
if(iter != stat_cache.end()){
|
||||
stat_cache.erase(iter);
|
||||
}
|
||||
}
|
||||
pthread_mutex_unlock(&stat_cache_lock);
|
||||
pthread_mutex_unlock(&StatCache::stat_cache_lock);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void truncate_stat_cache() {
|
||||
string path_to_delete;
|
||||
unsigned int hit_count = 0;
|
||||
unsigned int lowest_hit_count = 0;
|
||||
//-------------------------------------------------------------------
|
||||
// Functions
|
||||
//-------------------------------------------------------------------
|
||||
bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst)
|
||||
{
|
||||
headers_t::const_iterator iter;
|
||||
|
||||
pthread_mutex_lock(&stat_cache_lock);
|
||||
stat_cache_t::iterator iter;
|
||||
for(iter = stat_cache.begin(); iter != stat_cache.end(); iter++) {
|
||||
hit_count = (* iter).second.hit_count;
|
||||
if(!path || !pst){
|
||||
return false;
|
||||
}
|
||||
memset(pst, 0, sizeof(struct stat));
|
||||
|
||||
if(!lowest_hit_count) {
|
||||
lowest_hit_count = hit_count;
|
||||
path_to_delete = (* iter).first;
|
||||
}
|
||||
if(lowest_hit_count > hit_count){
|
||||
path_to_delete = (* iter).first;
|
||||
}
|
||||
pst->st_nlink = 1; // see fuse FAQ
|
||||
|
||||
// mode
|
||||
iter = meta.find("x-amz-meta-mode");
|
||||
if(iter != meta.end()){
|
||||
pst->st_mode = get_mode((*iter).second.c_str());
|
||||
}
|
||||
|
||||
stat_cache.erase(path_to_delete);
|
||||
pthread_mutex_unlock(&stat_cache_lock);
|
||||
// content-type
|
||||
string strConType;
|
||||
iter = meta.find("Content-Type");
|
||||
if(iter != meta.end()){
|
||||
strConType = (*iter).second;
|
||||
}
|
||||
if(strConType == "application/x-directory"){
|
||||
pst->st_mode |= S_IFDIR;
|
||||
}else if(0 < strlen(path) && '/' == path[strlen(path) - 1]){
|
||||
if(strConType == "binary/octet-stream" || strConType == "application/octet-stream"){
|
||||
pst->st_mode |= S_IFDIR;
|
||||
}else{
|
||||
pst->st_mode |= S_IFREG;
|
||||
}
|
||||
}else{
|
||||
pst->st_mode |= S_IFREG;
|
||||
}
|
||||
|
||||
FGPRINT(" purged %s from the stat cache\n", path_to_delete.c_str());
|
||||
// blocks
|
||||
if(S_ISREG(pst->st_mode)){
|
||||
pst->st_blocks = get_blocks(pst->st_size);
|
||||
}
|
||||
|
||||
// mtime
|
||||
iter = meta.find("x-amz-meta-mtime");
|
||||
if(iter != meta.end()){
|
||||
pst->st_mtime = get_mtime((*iter).second.c_str());
|
||||
}
|
||||
if(pst->st_mtime == 0) {
|
||||
iter = meta.find("Last-Modified");
|
||||
if(iter != meta.end()){
|
||||
pst->st_mtime = get_lastmodified((*iter).second.c_str());
|
||||
}
|
||||
}
|
||||
if(-1 == pst->st_mtime){
|
||||
pst->st_mtime = 0;
|
||||
}
|
||||
|
||||
// size
|
||||
iter = meta.find("Content-Length");
|
||||
if(iter != meta.end()){
|
||||
pst->st_size = get_size((*iter).second.c_str());
|
||||
}
|
||||
|
||||
// uid/gid
|
||||
iter = meta.find("x-amz-meta-uid");
|
||||
if(iter != meta.end()){
|
||||
pst->st_uid = get_uid((*iter).second.c_str());
|
||||
}
|
||||
iter = meta.find("x-amz-meta-gid");
|
||||
if(iter != meta.end()){
|
||||
pst->st_gid = get_gid((*iter).second.c_str());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
84
src/cache.h
84
src/cache.h
@ -1,29 +1,89 @@
|
||||
#ifndef S3FS_CACHE_H_
|
||||
#define S3FS_CACHE_H_
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/types.h>
|
||||
#include <unistd.h>
|
||||
#include "common.h"
|
||||
|
||||
//
|
||||
// Struct
|
||||
//
|
||||
struct stat_cache_entry {
|
||||
struct stat stbuf;
|
||||
struct stat stbuf;
|
||||
unsigned long hit_count;
|
||||
time_t cache_date;
|
||||
time_t cache_date;
|
||||
headers_t meta;
|
||||
|
||||
stat_cache_entry() : hit_count(0), cache_date(0) {}
|
||||
stat_cache_entry() : hit_count(0), cache_date(0) {
|
||||
memset(&stbuf, 0, sizeof(struct stat));
|
||||
meta.clear();
|
||||
}
|
||||
};
|
||||
|
||||
typedef std::map<std::string, struct stat_cache_entry> stat_cache_t; // key=path
|
||||
|
||||
//
|
||||
// Class
|
||||
//
|
||||
class StatCache
|
||||
{
|
||||
private:
|
||||
static StatCache singleton;
|
||||
static pthread_mutex_t stat_cache_lock;
|
||||
stat_cache_t stat_cache;
|
||||
bool IsExpireTime;
|
||||
time_t ExpireTime;
|
||||
unsigned long CacheSize;
|
||||
|
||||
private:
|
||||
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag);
|
||||
// Truncate stat cache
|
||||
bool TruncateCache(void);
|
||||
|
||||
public:
|
||||
StatCache();
|
||||
~StatCache();
|
||||
|
||||
// Reference singleton
|
||||
static StatCache* getStatCacheData(void) {
|
||||
return &singleton;
|
||||
}
|
||||
|
||||
// Attribute
|
||||
unsigned long GetCacheSize(void) const;
|
||||
unsigned long SetCacheSize(unsigned long size);
|
||||
time_t GetExpireTime(void) const;
|
||||
time_t SetExpireTime(time_t expire);
|
||||
time_t UnsetExpireTime(void);
|
||||
|
||||
// Get stat cache
|
||||
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck = true) {
|
||||
return GetStat(key, pst, meta, overcheck, NULL);
|
||||
}
|
||||
bool GetStat(std::string& key, struct stat* pst, bool overcheck = true) {
|
||||
return GetStat(key, pst, NULL, overcheck, NULL);
|
||||
}
|
||||
bool GetStat(std::string& key, headers_t* meta, bool overcheck = true) {
|
||||
return GetStat(key, NULL, meta, overcheck, NULL);
|
||||
}
|
||||
bool HasStat(std::string& key, bool overcheck = true) {
|
||||
return GetStat(key, NULL, NULL, overcheck, NULL);
|
||||
}
|
||||
bool HasStat(std::string& key, const char* etag, bool overcheck = true) {
|
||||
return GetStat(key, NULL, NULL, overcheck, etag);
|
||||
}
|
||||
|
||||
// Add stat cache
|
||||
bool AddStat(std::string& key, headers_t& meta);
|
||||
|
||||
// Delete stat cache
|
||||
bool DelStat(const char* key);
|
||||
bool DelStat(std::string& key) {
|
||||
return DelStat(key.c_str());
|
||||
}
|
||||
};
|
||||
|
||||
//
|
||||
// Functions
|
||||
//
|
||||
int init_stat_cache_mutex(void);
|
||||
int destroy_stat_cache_mutex(void);
|
||||
int get_stat_cache_entry(const char *path, struct stat *buf);
|
||||
void add_stat_cache_entry(const char *path, struct stat *st);
|
||||
void delete_stat_cache_entry(const char *path);
|
||||
void truncate_stat_cache();
|
||||
bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst);
|
||||
|
||||
#endif // S3FS_CACHE_H_
|
||||
|
@ -33,9 +33,6 @@ typedef std::map<std::string, std::string> headers_t;
|
||||
//
|
||||
extern bool debug;
|
||||
extern bool foreground;
|
||||
extern unsigned long max_stat_cache_size;
|
||||
extern time_t stat_cache_expire_time;
|
||||
extern int is_stat_cache_expire_time;
|
||||
extern int retries;
|
||||
extern long connect_timeout;
|
||||
extern time_t readwrite_timeout;
|
||||
|
@ -212,6 +212,7 @@ int curl_get_headers(const char *path, headers_t &meta)
|
||||
|
||||
// file exists in s3
|
||||
// fixme: clean this up.
|
||||
meta.clear();
|
||||
for (headers_t::iterator iter = responseHeaders.begin(); iter != responseHeaders.end(); ++iter) {
|
||||
string key = (*iter).first;
|
||||
string value = (*iter).second;
|
||||
|
669
src/s3fs.cpp
669
src/s3fs.cpp
File diff suppressed because it is too large
Load Diff
@ -65,7 +65,7 @@ string get_realpath(const char *path) {
|
||||
// If there are "dir" and "dir/" object on S3, s3fs only recognizes "dir/".
|
||||
// On this case, user can not know the "dir" object.
|
||||
//
|
||||
int insert_object(const char *name, struct s3_object **head)
|
||||
int insert_object(const char* name, const char* etag, struct s3_object** head)
|
||||
{
|
||||
struct s3_object *cur_object;
|
||||
struct s3_object *new_object;
|
||||
@ -88,21 +88,31 @@ int insert_object(const char *name, struct s3_object **head)
|
||||
is_have_cdelimiter = 1;
|
||||
}
|
||||
if(cLen == nLen){
|
||||
// same object
|
||||
if(is_have_cdelimiter == is_have_ndelimiter){
|
||||
// perfect same object
|
||||
// perfect same object, replace only etag.
|
||||
}else if(is_have_cdelimiter){
|
||||
// already set "dir/", so not need to add this.
|
||||
return 0;
|
||||
}else{
|
||||
// new object is "dir/", replace name and etag
|
||||
free(cur_object->name);
|
||||
if(NULL == (cur_object->name = strdup(name))){
|
||||
printf("insert_object: could not allocate memory\n");
|
||||
S3FS_FUSE_EXIT();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
if(is_have_cdelimiter){
|
||||
// already set "dir/"
|
||||
return 0;
|
||||
// replace etag.
|
||||
if(cur_object->etag){
|
||||
free(cur_object->etag);
|
||||
cur_object->etag = NULL;
|
||||
}
|
||||
// new object is "dir/", replace name.
|
||||
free(cur_object->name);
|
||||
if(NULL == (cur_object->name = strdup(name))){
|
||||
printf("insert_object: could not allocate memory\n");
|
||||
S3FS_FUSE_EXIT();
|
||||
return -1;
|
||||
if(etag){
|
||||
if(NULL == (cur_object->etag = strdup(etag))){
|
||||
printf("insert_object: could not allocate memory\n");
|
||||
S3FS_FUSE_EXIT();
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
@ -110,7 +120,7 @@ int insert_object(const char *name, struct s3_object **head)
|
||||
}
|
||||
|
||||
// Not found same object.
|
||||
new_object = (struct s3_object *) malloc(sizeof(struct s3_object));
|
||||
new_object = (struct s3_object*)malloc(sizeof(struct s3_object));
|
||||
if(new_object == NULL) {
|
||||
printf("insert_object: could not allocate memory\n");
|
||||
S3FS_FUSE_EXIT();
|
||||
@ -123,12 +133,23 @@ int insert_object(const char *name, struct s3_object **head)
|
||||
S3FS_FUSE_EXIT();
|
||||
return -1;
|
||||
}
|
||||
if(etag){
|
||||
if(NULL == (new_object->etag = strdup(etag))){
|
||||
free(new_object->name);
|
||||
free(new_object);
|
||||
printf("insert_object: could not allocate memory\n");
|
||||
S3FS_FUSE_EXIT();
|
||||
return -1;
|
||||
}
|
||||
}else{
|
||||
new_object->etag = NULL;
|
||||
}
|
||||
|
||||
if((*head) == NULL)
|
||||
if((*head) == NULL){
|
||||
new_object->next = NULL;
|
||||
else
|
||||
}else{
|
||||
new_object->next = (*head);
|
||||
|
||||
}
|
||||
*head = new_object;
|
||||
|
||||
return 0;
|
||||
@ -137,6 +158,9 @@ int insert_object(const char *name, struct s3_object **head)
|
||||
int free_object(struct s3_object *object)
|
||||
{
|
||||
free(object->name);
|
||||
if(object->etag){
|
||||
free(object->etag);
|
||||
}
|
||||
free(object);
|
||||
object = NULL;
|
||||
|
||||
@ -400,6 +424,16 @@ blkcnt_t get_blocks(off_t size)
|
||||
return size / 512 + 1;
|
||||
}
|
||||
|
||||
time_t get_lastmodified(const char* s)
|
||||
{
|
||||
struct tm tm;
|
||||
if(!s){
|
||||
return 0L;
|
||||
}
|
||||
strptime(s, "%a, %d %b %Y %H:%M:%S %Z", &tm);
|
||||
return mktime(&tm); // GMT
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------
|
||||
// Help
|
||||
//-------------------------------------------------------------------
|
||||
@ -467,6 +501,8 @@ void show_help (void)
|
||||
" disable registing xml name space for response of \n"
|
||||
" ListBucketResult and ListVersionsResult etc. Default name \n"
|
||||
" space is looked up from \"http://s3.amazonaws.com/doc/2006-03-01\".\n"
|
||||
" This option should not be specified now, because s3fs looks up\n"
|
||||
" xmlns automatically after v1.66.\n"
|
||||
"\n"
|
||||
" nocopyapi - for other incomplete compatibility object storage.\n"
|
||||
" For a distributed object storage which is compatibility S3\n"
|
||||
|
@ -5,7 +5,8 @@
|
||||
// Typedef
|
||||
//-------------------------------------------------------------------
|
||||
struct s3_object {
|
||||
char *name;
|
||||
char* name;
|
||||
char* etag;
|
||||
struct s3_object *next;
|
||||
};
|
||||
|
||||
@ -23,7 +24,7 @@ typedef struct mvnode {
|
||||
//-------------------------------------------------------------------
|
||||
std::string get_realpath(const char *path);
|
||||
|
||||
int insert_object(const char *name, struct s3_object **head);
|
||||
int insert_object(const char* name, const char* etag, struct s3_object** head);
|
||||
int free_object(struct s3_object *object);
|
||||
int free_object_list(struct s3_object *head);
|
||||
|
||||
@ -44,6 +45,7 @@ mode_t get_mode(const char *s);
|
||||
uid_t get_uid(const char *s);
|
||||
gid_t get_gid(const char *s);
|
||||
blkcnt_t get_blocks(off_t size);
|
||||
time_t get_lastmodified(const char* s);
|
||||
|
||||
void show_usage(void);
|
||||
void show_help(void);
|
||||
|
Loading…
Reference in New Issue
Block a user