Changed codes for issue: 27(+)

1) Feature Request: Compatability with other S3FS clients(Issue: 27)
    Rechanges source code.

2) For other S3 clients
    Supports the directory which is no objects.
    If there is a object which has "/" charactor(ex. "<bucket>/dir/file"), the directory("dir") object is no object.
    Exsample, you can upload the object which name is "s3://bucket/dir/file" by the s3cmd.
    Then the "dir" is not object in bucket("dir").
    This s3fs codes understands this case.



git-svn-id: http://s3fs.googlecode.com/svn/trunk@414 df820570-a93a-0410-bd06-b72b767a4274
This commit is contained in:
ggtakec@gmail.com 2013-04-29 14:31:10 +00:00
parent 36447a23eb
commit b973eaae44
5 changed files with 330 additions and 214 deletions

View File

@ -101,7 +101,7 @@ time_t StatCache::UnsetExpireTime(void)
return old;
}
bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag)
bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce)
{
bool is_delete_cache = false;
string strpath = key;
@ -144,7 +144,9 @@ bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool ove
meta->clear();
(*meta) = (*iter).second.meta;
}
if(pisforce != NULL){
(*pisforce) = (*iter).second.isforce;
}
(*iter).second.hit_count++;
pthread_mutex_unlock(&StatCache::stat_cache_lock);
return true;
@ -163,7 +165,7 @@ bool StatCache::GetStat(string& key, struct stat* pst, headers_t* meta, bool ove
return false;
}
bool StatCache::AddStat(std::string& key, headers_t& meta)
bool StatCache::AddStat(std::string& key, headers_t& meta, bool forcedir)
{
if(CacheSize< 1){
return true;
@ -177,7 +179,7 @@ bool StatCache::AddStat(std::string& key, headers_t& meta)
}
struct stat st;
if(!convert_header_to_stat(key.c_str(), meta, &st)){
if(!convert_header_to_stat(key.c_str(), meta, &st, forcedir)){
return false;
}
@ -185,6 +187,7 @@ bool StatCache::AddStat(std::string& key, headers_t& meta)
stat_cache[key].stbuf = st;
stat_cache[key].hit_count = 0;
stat_cache[key].cache_date = time(NULL); // Set time.
stat_cache[key].isforce = forcedir;
//copy only some keys
for (headers_t::iterator iter = meta.begin(); iter != meta.end(); ++iter) {
@ -272,7 +275,7 @@ bool StatCache::DelStat(const char* key)
//-------------------------------------------------------------------
// Functions
//-------------------------------------------------------------------
bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst)
bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst, bool forcedir)
{
headers_t::const_iterator iter;
@ -295,16 +298,20 @@ bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst)
if(iter != meta.end()){
strConType = (*iter).second;
}
if(strConType == "application/x-directory"){
if(forcedir){
pst->st_mode |= S_IFDIR;
}else if(0 < strlen(path) && '/' == path[strlen(path) - 1]){
if(strConType == "binary/octet-stream" || strConType == "application/octet-stream"){
}else{
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;
}
}else{
pst->st_mode |= S_IFREG;
}
// blocks

View File

@ -11,8 +11,9 @@ struct stat_cache_entry {
unsigned long hit_count;
time_t cache_date;
headers_t meta;
bool isforce;
stat_cache_entry() : hit_count(0), cache_date(0) {
stat_cache_entry() : hit_count(0), cache_date(0), isforce(false) {
memset(&stbuf, 0, sizeof(struct stat));
meta.clear();
}
@ -34,7 +35,7 @@ class StatCache
unsigned long CacheSize;
private:
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag);
bool GetStat(std::string& key, struct stat* pst, headers_t* meta, bool overcheck, const char* petag, bool* pisforce);
// Truncate stat cache
bool TruncateCache(void);
@ -55,24 +56,24 @@ class StatCache
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, headers_t* meta, bool overcheck = true, bool* pisforce = NULL) {
return GetStat(key, pst, meta, overcheck, NULL, pisforce);
}
bool GetStat(std::string& key, struct stat* pst, bool overcheck = true) {
return GetStat(key, pst, NULL, overcheck, NULL);
return GetStat(key, pst, NULL, overcheck, NULL, NULL);
}
bool GetStat(std::string& key, headers_t* meta, bool overcheck = true) {
return GetStat(key, NULL, meta, overcheck, NULL);
return GetStat(key, NULL, meta, overcheck, NULL, NULL);
}
bool HasStat(std::string& key, bool overcheck = true) {
return GetStat(key, NULL, NULL, overcheck, NULL);
return GetStat(key, NULL, NULL, overcheck, NULL, NULL);
}
bool HasStat(std::string& key, const char* etag, bool overcheck = true) {
return GetStat(key, NULL, NULL, overcheck, etag);
return GetStat(key, NULL, NULL, overcheck, etag, NULL);
}
// Add stat cache
bool AddStat(std::string& key, headers_t& meta);
bool AddStat(std::string& key, headers_t& meta, bool forcedir = false);
// Delete stat cache
bool DelStat(const char* key);
@ -84,6 +85,6 @@ class StatCache
//
// Functions
//
bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst);
bool convert_header_to_stat(const char* path, headers_t& meta, struct stat* pst, bool forcedir = false);
#endif // S3FS_CACHE_H_

View File

@ -56,6 +56,10 @@ using namespace std;
#define DIRTYPE_NEW 0
#define DIRTYPE_OLD 1
#define DIRTYPE_FOLDER 2
#define DIRTYPE_NOOBJ 3
#define IS_REPLACEDIR(type) (DIRTYPE_OLD == type || DIRTYPE_FOLDER == type || DIRTYPE_NOOBJ == type)
#define IS_RMTYPEDIR(type) (DIRTYPE_OLD == type || DIRTYPE_FOLDER == type)
//-------------------------------------------------------------------
// Typedef
@ -120,12 +124,13 @@ static s3fs_pathtofd_t s3fs_pathtofd; // path -> fd
// Static functions : prototype
//-------------------------------------------------------------------
static bool is_special_name_folder_object(const char *path);
static int chk_dir_object_type(const char *path, string& strpath, string& strdelpath, headers_t* pmeta = NULL, int* pDirType = NULL);
static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t* pmeta = NULL, bool overcheck = true);
static int chk_dir_object_type(const char *path, string& newpath, string& nowpath, string& nowcache, headers_t* pmeta = NULL, int* pDirType = NULL);
static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t* pmeta = NULL, bool overcheck = true, bool* pisforce = NULL);
static int check_object_access(const char *path, int mask, struct stat* pstbuf);
static int check_object_owner(const char *path, struct stat* pstbuf);
static int check_parent_object_access(const char *path, int mask);
static int list_bucket(const char *path, S3ObjList& head, const char* delimiter);
static int directory_empty(const char *path);
static bool is_truncated(const char *xml);
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);
@ -200,69 +205,92 @@ static bool is_special_name_folder_object(const char *path)
return true;
}
static int chk_dir_object_type(const char *path, string& strpath, string& strdelpath, headers_t* pmeta, int* pDirType)
// [Detail]
// This function is complicated for checking directory object type.
// Arguments is used for deleting cache/path, and remake directory object.
// Please see the codes which calls this function.
//
// path: target path
// newpath: should be object path for making/putting/getting after checking
// nowpath: now object name for deleting after checking
// nowcache: now cache path for deleting after checking
// pmeta: headers map
// pDirType: directory object type
//
static int chk_dir_object_type(const char *path, string& newpath, string& nowpath, string& nowcache, headers_t* pmeta, int* pDirType)
{
int result = -1;
strpath = path;
if(pDirType){
*pDirType= DIRTYPE_NEW;
int TypeTmp;
int result = -1;
bool isforce = false;
int* pType = pDirType ? pDirType : &TypeTmp;
// Normalize new path.
newpath = path;
if('/' != newpath[newpath.length() - 1]){
string::size_type Pos;
if(string::npos != (Pos = newpath.find("_$folder$", 0))){
newpath = newpath.substr(0, Pos);
}
newpath += "/";
}
// At first, if not have "/", check path with "/".
if('/' != strpath[strpath.length() - 1]){
strpath += "/";
strdelpath = strpath;
result = get_object_attribute(strpath.c_str(), NULL, pmeta, false);
}
if(0 == result){
// Found "dir/" --> Check for "_$folder$"
if(is_special_name_folder_object(strpath.c_str())){
if(0 < strpath.length() && '/' == strpath[strpath.length() - 1]){
strpath = strpath.substr(0, strpath.length() - 1);
}
strdelpath = strpath + "_$folder$";
if(pDirType){
*pDirType = DIRTYPE_FOLDER;
// Alwayes check "dir/" at first.
if(0 == (result = get_object_attribute(newpath.c_str(), NULL, pmeta, false, &isforce))){
// Found "dir/" cache --> Check for "_$folder$", "no dir object"
nowcache = newpath;
if(is_special_name_folder_object(newpath.c_str())){
// "_$folder$" type.
(*pType) = DIRTYPE_FOLDER;
nowpath = newpath.substr(0, newpath.length() - 1) + "_$folder$"; // cut and add
}else if(isforce){
// "no dir object" type.
(*pType) = DIRTYPE_NOOBJ;
nowpath = "";
}else{
nowpath = path;
if(0 < nowpath.length() && '/' == nowpath[nowpath.length() - 1]){
// "dir/" type
(*pType) = DIRTYPE_NEW;
}else{
// "dir" type
(*pType) = DIRTYPE_OLD;
}
}
}else{
// Need to chack old type directory("dir").
strpath = path;
strdelpath = strpath;
if(0 == (result = get_object_attribute(strpath.c_str(), NULL, pmeta, false))){
if(0 < strpath.length() && '/' != strpath[strpath.length() - 1]){
if(pDirType){
*pDirType = DIRTYPE_OLD;
}
// Check "dir"
nowpath = newpath.substr(0, newpath.length() - 1);
if(0 == (result = get_object_attribute(nowpath.c_str(), NULL, pmeta, false, &isforce))){
// Found "dir" cache --> this case is only "dir" type.
// Because, if object is "_$folder$" or "no dir object", the cache is "dir/" type.
// (But "no dir objet" is checked here.)
nowcache = nowpath;
if(isforce){
(*pType) = DIRTYPE_NOOBJ;
nowpath = "";
}else{
// Found "dir/" --> Check for "_$folder$"
if(is_special_name_folder_object(strpath.c_str())){
strpath = strpath.substr(0, strpath.length() - 1);
strdelpath = strpath + "_$folder$";
if(pDirType){
*pDirType = DIRTYPE_FOLDER;
}
}
(*pType) = DIRTYPE_OLD;
}
}else{
// Check for "_$folder$"
if(is_special_name_folder_object(strpath.c_str())){
if(0 < strpath.length() && '/' == strpath[strpath.length() - 1]){
strpath = strpath.substr(0, strpath.length() - 1);
}
strdelpath = strpath + "_$folder$";
if(pDirType){
*pDirType = DIRTYPE_FOLDER;
}
result = get_object_attribute(strpath.c_str(), NULL, pmeta, false);
// Not found cache --> check for "_$folder$" and "no dir object".
nowcache = ""; // This case is no cahce.
nowpath += "_$folder$";
if(is_special_name_folder_object(nowpath.c_str())){
// "_$folder$" type.
(*pType) = DIRTYPE_FOLDER;
result = 0; // result is OK.
}else if(-ENOTEMPTY == directory_empty(newpath.c_str())){
// "no dir object" type.
(*pType) = DIRTYPE_NOOBJ;
nowpath = ""; // now path.
result = 0; // result is OK.
}else{
// Error: Unknown type.
(*pType) = DIRTYPE_UNKNOWN;
newpath = "";
nowpath = "";
}
}
}
if(0 != result){
if(pDirType){
*pDirType = DIRTYPE_UNKNOWN;
}
}
return result;
}
@ -270,7 +298,7 @@ static int chk_dir_object_type(const char *path, string& strpath, string& strdel
// Get object attributes with stat cache.
// This function is base for s3fs_getattr().
//
static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t* pmeta, bool overcheck)
static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t* pmeta, bool overcheck, bool* pisforce)
{
int result = -1;
struct stat tmpstbuf;
@ -280,6 +308,7 @@ static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t
string strpath;
string s3_realpath;
string::size_type Pos;
bool forcedir = false;
//FGPRINT(" get_object_attribute[path=%s]\n", path);
@ -299,7 +328,10 @@ static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t
strpath += "/";
}
}
if(StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck)){
if(pisforce){
(*pisforce) = false;
}
if(StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck, pisforce)){
return 0;
}
@ -319,15 +351,32 @@ static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t
strpath = path;
s3_realpath = get_realpath(strpath.c_str());
if(0 != (result = curl_get_headers(s3_realpath.c_str(), (*pheader)))){
if(overcheck && string::npos == strpath.find("_$folder$", 0)){
// check for s3fox etc
strpath += "_$folder$";
s3_realpath = get_realpath(strpath.c_str());
if(0 != (result = curl_get_headers(s3_realpath.c_str(), (*pheader)))){
return result;
// Not found --> check( if overcheck )
if(overcheck){
if(string::npos == strpath.find("_$folder$", 0)){
// path doesn't have "_$folder$" --> check for s3fox etc
strpath += "_$folder$";
s3_realpath = get_realpath(strpath.c_str());
result = curl_get_headers(s3_realpath.c_str(), (*pheader));
}
if(0 == result){
// found "_$folder$" object.
strpath = path; // reset original
strpath += "/";
}else{
// path does not have "_$folder$" --> check "no dir obejct".
if(-ENOTEMPTY == directory_empty(path)){
// found "no dir obejct".
forcedir = true;
strpath = path; // reset original
strpath += "/";
if(pisforce){
(*pisforce) = true;
}
}else{
return result;
}
}
strpath = path; // reset original
strpath += "/";
}else{
return result;
}
@ -342,11 +391,11 @@ static int get_object_attribute(const char *path, struct stat *pstbuf, headers_t
}
// add into stat cache
if(!StatCache::getStatCacheData()->AddStat(strpath, (*pheader))){
if(!StatCache::getStatCacheData()->AddStat(strpath, (*pheader), forcedir)){
FGPRINT(" get_object_attribute: failed adding stat cache [path=%s]\n", strpath.c_str());
return -ENOENT;
}
if(!StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck)){
if(!StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck, pisforce)){
FGPRINT(" get_object_attribute: failed getting added stat cache [path=%s]\n", strpath.c_str());
return -ENOENT;
}
@ -1821,6 +1870,8 @@ static int s3fs_rmdir(const char *path)
StatCache::getStatCacheData()->DelStat(strpath.c_str());
}
}
// If there is no "dir" and "dir/" object(this case is made by s3cmd/s3sync),
// the cache key is "dir/". So we get error only onece(delete "dir/").
// check for "_$folder$" object.
// This processing is necessary for other S3 clients compatibility.
@ -2065,13 +2116,17 @@ static int clone_directory_object(const char *from, const char *to)
return result;
}
static int rename_directory(const char *from, const char *to) {
static int rename_directory(const char *from, const char *to)
{
S3ObjList head;
s3obj_list_t headlist;
string strfrom = from ? from : ""; // from is without "/".
string strto = to ? to : ""; // to is without "/" too.
string basepath = strfrom + "/";
string strdelpath;
string newpath; // should be from name(not used)
string nowcache; // now cache path(not used)
int DirType;
bool normdir;
MVNODE* mn_head = NULL;
MVNODE* mn_tail = NULL;
MVNODE* mn_cur;
@ -2086,12 +2141,18 @@ static int rename_directory(const char *from, const char *to) {
// Initiate and Add base directory into MVNODE struct.
//
strto += "/";
if(0 == chk_dir_object_type(from, strfrom, strdelpath)){
if(NULL == (add_mvnode(&mn_head, &mn_tail, strdelpath.c_str(), strto.c_str(), true))){
if(0 == chk_dir_object_type(from, newpath, strfrom, nowcache, NULL, &DirType) && DIRTYPE_UNKNOWN != DirType){
if(DIRTYPE_NOOBJ != DirType){
normdir = false;
}else{
normdir = true;
strfrom = from; // from directory is not removed, but from directory attr is needed.
}
if(NULL == (add_mvnode(&mn_head, &mn_tail, strfrom.c_str(), strto.c_str(), true, normdir))){
return -ENOMEM;
}
}else{
// No base directory: maybe a case of made no directory by s3cmd.
// Something wrong about "from" directory.
}
//
@ -2103,8 +2164,9 @@ static int rename_directory(const char *from, const char *to) {
FGPRINT(" rename_directory list_bucket returns error.\n");
return result;
}
head.GetNameList(headlist); // get name without "/".
S3ObjList::MakeHierarchizedList(headlist, false); // add hierarchized dir.
head.GetNameList(headlist); // get name without "/".
s3obj_list_t::const_iterator liter;
for(liter = headlist.begin(); headlist.end() != liter; liter++){
// make "from" and "to" object name.
@ -2120,17 +2182,23 @@ static int rename_directory(const char *from, const char *to) {
}
if(S_ISDIR(stbuf.st_mode)){
is_dir = true;
if(0 != chk_dir_object_type(from_name.c_str(), from_name, strdelpath)){
FGPRINT(" rename_directory - failed to get %s object directory type.\n", from_name.c_str());
if(0 != chk_dir_object_type(from_name.c_str(), newpath, from_name, nowcache, NULL, &DirType) || DIRTYPE_UNKNOWN == DirType){
FGPRINT(" rename_directory - failed to get %s%s object directory type.\n", basepath.c_str(), (*liter).c_str());
continue;
}
if(DIRTYPE_NOOBJ != DirType){
normdir = false;
}else{
normdir = true;
from_name = basepath + (*liter); // from directory is not removed, but from directory attr is needed.
}
}else{
is_dir = false;
strdelpath = from_name;
is_dir = false;
normdir = false;
}
// push this one onto the stack
if(NULL == add_mvnode(&mn_head, &mn_tail, strdelpath.c_str(), to_name.c_str(), is_dir)){
if(NULL == add_mvnode(&mn_head, &mn_tail, from_name.c_str(), to_name.c_str(), is_dir, normdir)){
return -ENOMEM;
}
}
@ -2140,7 +2208,7 @@ static int rename_directory(const char *from, const char *to) {
//
// rename directory objects.
for(mn_cur = mn_head; mn_cur; mn_cur = mn_cur->next){
if(mn_cur->is_dir){
if(mn_cur->is_dir && mn_cur->old_path && '\0' != mn_cur->old_path[0]){
if(0 != (result = clone_directory_object(mn_cur->old_path, mn_cur->new_path))){
FGPRINT(" rename_directory - failed(%d) to rename %s directory object to %s.\n", result, mn_cur->old_path, mn_cur->new_path);
SYSLOGERR("clone_directory_object returned an error(%d)", result);
@ -2170,12 +2238,17 @@ static int rename_directory(const char *from, const char *to) {
// Iterate over old the directories, bottoms up and remove
for(mn_cur = mn_tail; mn_cur; mn_cur = mn_cur->prev){
if(mn_cur->is_dir){
if(0 != (result = s3fs_rmdir(mn_cur->old_path))){
FGPRINT(" rename_directory - failed(%d) to remove %s directory object.\n", result, mn_cur->old_path);
SYSLOGERR("s3fs_rmdir returned an error(%d)", result);
free_mvnodes(mn_head);
return -EIO;
if(mn_cur->is_dir && mn_cur->old_path && '\0' != mn_cur->old_path[0]){
if(!(mn_cur->is_normdir)){
if(0 != (result = s3fs_rmdir(mn_cur->old_path))){
FGPRINT(" rename_directory - failed(%d) to remove %s directory object.\n", result, mn_cur->old_path);
SYSLOGERR("s3fs_rmdir returned an error(%d)", result);
free_mvnodes(mn_head);
return -EIO;
}
}else{
// cache clear.
StatCache::getStatCacheData()->DelStat(mn_cur->old_path);
}
}
}
@ -2229,7 +2302,8 @@ static int s3fs_chmod(const char *path, mode_t mode)
int result;
string s3_realpath;
string strpath;
string strdel;
string newpath;
string nowcache;
headers_t meta;
struct stat stbuf;
int nDirType = DIRTYPE_UNKNOWN;
@ -2244,11 +2318,11 @@ static int s3fs_chmod(const char *path, mode_t mode)
}
if(S_ISDIR(stbuf.st_mode)){
result = chk_dir_object_type(path, strpath, strdel, &meta, &nDirType);
s3_realpath = get_realpath(strdel.c_str());
result = chk_dir_object_type(path, newpath, strpath, nowcache, &meta, &nDirType);
s3_realpath = get_realpath(strpath.c_str());
}else{
strpath = path;
strdel = strpath;
nowcache = strpath;
s3_realpath = get_realpath(strpath.c_str());
result = get_object_attribute(strpath.c_str(), NULL, &meta);
}
@ -2256,21 +2330,22 @@ static int s3fs_chmod(const char *path, mode_t mode)
return result;
}
if(S_ISDIR(stbuf.st_mode) && DIRTYPE_NEW != nDirType){
// directory object of old version
// Need to remove old dir("dir") and make new dir("dir/")
if(S_ISDIR(stbuf.st_mode) && IS_REPLACEDIR(nDirType)){
// Should rebuild directory object(except new type)
// Need to remove old dir("dir" etc) and make new dir("dir/")
// At first, remove directory old object
if(0 != (result = curl_delete(s3_realpath.c_str()))){
return result;
if(IS_RMTYPEDIR(nDirType)){
if(0 != (result = curl_delete(s3_realpath.c_str()))){
return result;
}
}
StatCache::getStatCacheData()->DelStat(strdel);
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(strpath.c_str(), mode, stbuf.st_mtime, stbuf.st_uid, stbuf.st_gid))){
if(0 != (result = create_directory_object(newpath.c_str(), mode, stbuf.st_mtime, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
// normal object or directory object of newer version
meta["x-amz-meta-mode"] = str(mode);
@ -2280,7 +2355,7 @@ static int s3fs_chmod(const char *path, mode_t mode)
if(put_headers(strpath.c_str(), meta) != 0){
return -EIO;
}
StatCache::getStatCacheData()->DelStat(strdel);
StatCache::getStatCacheData()->DelStat(nowcache);
}
return 0;
@ -2290,7 +2365,8 @@ static int s3fs_chmod_nocopy(const char *path, mode_t mode) {
int result;
string s3_realpath;
string strpath;
string strdel;
string newpath;
string nowcache;
headers_t meta;
struct stat stbuf;
int nDirType = DIRTYPE_UNKNOWN;
@ -2306,11 +2382,11 @@ static int s3fs_chmod_nocopy(const char *path, mode_t mode) {
// Get attributes
if(S_ISDIR(stbuf.st_mode)){
result = chk_dir_object_type(path, strpath, strdel, &meta, &nDirType);
s3_realpath = get_realpath(strdel.c_str());
result = chk_dir_object_type(path, newpath, strpath, nowcache, &meta, &nDirType);
s3_realpath = get_realpath(strpath.c_str());
}else{
strpath = path;
strdel = strpath;
nowcache = strpath;
s3_realpath = get_realpath(strpath.c_str());
result = get_object_attribute(strpath.c_str(), NULL, &meta);
}
@ -2319,29 +2395,21 @@ static int s3fs_chmod_nocopy(const char *path, mode_t mode) {
}
if(S_ISDIR(stbuf.st_mode)){
if(DIRTYPE_NEW != nDirType){
// directory object of old version
// Need to remove old dir("dir") and make new dir("dir/")
// At first, remove directory old object
// Should rebuild all directory object
// Need to remove old dir("dir" etc) and make new dir("dir/")
// At first, remove directory old object
if(IS_RMTYPEDIR(nDirType)){
if(0 != (result = curl_delete(s3_realpath.c_str()))){
return result;
}
StatCache::getStatCacheData()->DelStat(strdel);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(strpath.c_str(), mode, stbuf.st_mtime, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
// directory object of new version
// Over put directory object.
if(0 != (result = create_directory_object(strpath.c_str(), mode, stbuf.st_mtime, stbuf.st_uid, stbuf.st_gid))){
return result;
}
StatCache::getStatCacheData()->DelStat(strdel);
}
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), mode, stbuf.st_mtime, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
// normal object or directory object of newer version
int fd;
@ -2377,7 +2445,7 @@ static int s3fs_chmod_nocopy(const char *path, mode_t mode) {
if(isclose){
close(fd);
}
StatCache::getStatCacheData()->DelStat(strdel);
StatCache::getStatCacheData()->DelStat(nowcache);
}
return result;
@ -2387,7 +2455,8 @@ static int s3fs_chown(const char *path, uid_t uid, gid_t gid) {
int result;
string s3_realpath;
string strpath;
string strdel;
string newpath;
string nowcache;
headers_t meta;
struct stat stbuf;
int nDirType = DIRTYPE_UNKNOWN;
@ -2402,11 +2471,11 @@ static int s3fs_chown(const char *path, uid_t uid, gid_t gid) {
}
if(S_ISDIR(stbuf.st_mode)){
result = chk_dir_object_type(path, strpath, strdel, &meta, &nDirType);
s3_realpath = get_realpath(strdel.c_str());
result = chk_dir_object_type(path, newpath, strpath, nowcache, &meta, &nDirType);
s3_realpath = get_realpath(strpath.c_str());
}else{
strpath = path;
strdel = strpath;
nowcache = strpath;
s3_realpath = get_realpath(strpath.c_str());
result = get_object_attribute(strpath.c_str(), NULL, &meta);
}
@ -2423,18 +2492,20 @@ static int s3fs_chown(const char *path, uid_t uid, gid_t gid) {
gid = grdata->gr_gid;
}
if(S_ISDIR(stbuf.st_mode) && DIRTYPE_NEW != nDirType){
// directory object of old version
// Need to remove old dir("dir") and make new dir("dir/")
if(S_ISDIR(stbuf.st_mode) && IS_REPLACEDIR(nDirType)){
// Should rebuild directory object(except new type)
// Need to remove old dir("dir" etc) and make new dir("dir/")
// At first, remove directory old object
if(0 != (result = curl_delete(s3_realpath.c_str()))){
return result;
if(IS_RMTYPEDIR(nDirType)){
if(0 != (result = curl_delete(s3_realpath.c_str()))){
return result;
}
}
StatCache::getStatCacheData()->DelStat(strdel);
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(strpath.c_str(), stbuf.st_mode, stbuf.st_mtime, uid, gid))){
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, stbuf.st_mtime, uid, gid))){
return result;
}
}else{
@ -2446,7 +2517,7 @@ static int s3fs_chown(const char *path, uid_t uid, gid_t gid) {
if(put_headers(strpath.c_str(), meta) != 0){
return -EIO;
}
StatCache::getStatCacheData()->DelStat(strdel);
StatCache::getStatCacheData()->DelStat(nowcache);
}
return 0;
@ -2456,7 +2527,8 @@ static int s3fs_chown_nocopy(const char *path, uid_t uid, gid_t gid) {
int result;
string s3_realpath;
string strpath;
string strdel;
string newpath;
string nowcache;
headers_t meta;
struct stat stbuf;
int nDirType = DIRTYPE_UNKNOWN;
@ -2472,11 +2544,11 @@ static int s3fs_chown_nocopy(const char *path, uid_t uid, gid_t gid) {
// Get attributes
if(S_ISDIR(stbuf.st_mode)){
result = chk_dir_object_type(path, strpath, strdel, &meta, &nDirType);
s3_realpath = get_realpath(strdel.c_str());
result = chk_dir_object_type(path, newpath, strpath, nowcache, &meta, &nDirType);
s3_realpath = get_realpath(strpath.c_str());
}else{
strpath = path;
strdel = strpath;
nowcache = strpath;
s3_realpath = get_realpath(strpath.c_str());
result = get_object_attribute(strpath.c_str(), NULL, &meta);
}
@ -2494,27 +2566,20 @@ static int s3fs_chown_nocopy(const char *path, uid_t uid, gid_t gid) {
}
if(S_ISDIR(stbuf.st_mode)){
if(DIRTYPE_NEW != nDirType){
// directory object of old version
// Need to remove old dir("dir") and make new dir("dir/")
// Should rebuild all directory object
// Need to remove old dir("dir" etc) and make new dir("dir/")
// At first, remove directory old object
// At first, remove directory old object
if(IS_RMTYPEDIR(nDirType)){
if(0 != (result = curl_delete(s3_realpath.c_str()))){
return result;
}
StatCache::getStatCacheData()->DelStat(strdel);
}
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(strpath.c_str(), stbuf.st_mode, stbuf.st_mtime, uid, gid))){
return result;
}
}else{
// directory object of new version
// Over put directory object.
if(0 != (result = create_directory_object(strpath.c_str(), stbuf.st_mode, stbuf.st_mtime, uid, gid))){
return result;
}
StatCache::getStatCacheData()->DelStat(strdel);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, stbuf.st_mtime, uid, gid))){
return result;
}
}else{
// normal object or directory object of newer version
@ -2553,7 +2618,7 @@ static int s3fs_chown_nocopy(const char *path, uid_t uid, gid_t gid) {
if(isclose){
close(fd);
}
StatCache::getStatCacheData()->DelStat(strdel);
StatCache::getStatCacheData()->DelStat(nowcache);
}
return result;
@ -3380,7 +3445,8 @@ static int s3fs_utimens(const char *path, const struct timespec ts[2]) {
int result;
string s3_realpath;
string strpath;
string strdel;
string newpath;
string nowcache;
headers_t meta;
struct stat stbuf;
int nDirType = DIRTYPE_UNKNOWN;
@ -3395,11 +3461,11 @@ static int s3fs_utimens(const char *path, const struct timespec ts[2]) {
}
if(S_ISDIR(stbuf.st_mode)){
result = chk_dir_object_type(path, strpath, strdel, &meta, &nDirType);
s3_realpath = get_realpath(strdel.c_str());
result = chk_dir_object_type(path, newpath, strpath, nowcache, &meta, &nDirType);
s3_realpath = get_realpath(strpath.c_str());
}else{
strpath = path;
strdel = strpath;
nowcache = strpath;
s3_realpath = get_realpath(strpath.c_str());
result = get_object_attribute(strpath.c_str(), NULL, &meta);
}
@ -3407,18 +3473,20 @@ static int s3fs_utimens(const char *path, const struct timespec ts[2]) {
return result;
}
if(S_ISDIR(stbuf.st_mode) && DIRTYPE_NEW != nDirType){
// directory object of old version
// Need to remove old dir("dir") and make new dir("dir/")
if(S_ISDIR(stbuf.st_mode) && IS_REPLACEDIR(nDirType)){
// Should rebuild directory object(except new type)
// Need to remove old dir("dir" etc) and make new dir("dir/")
// At first, remove directory old object
if(0 != (result = curl_delete(s3_realpath.c_str()))){
return result;
if(IS_RMTYPEDIR(nDirType)){
if(0 != (result = curl_delete(s3_realpath.c_str()))){
return result;
}
}
StatCache::getStatCacheData()->DelStat(strdel);
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(strpath.c_str(), stbuf.st_mode, ts[1].tv_sec, stbuf.st_uid, stbuf.st_gid))){
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, ts[1].tv_sec, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
@ -3429,7 +3497,7 @@ static int s3fs_utimens(const char *path, const struct timespec ts[2]) {
if(put_headers(strpath.c_str(), meta) != 0){
return -EIO;
}
StatCache::getStatCacheData()->DelStat(strdel);
StatCache::getStatCacheData()->DelStat(nowcache);
}
return 0;
@ -3439,7 +3507,8 @@ static int s3fs_utimens_nocopy(const char *path, const struct timespec ts[2]) {
int result;
string s3_realpath;
string strpath;
string strdel;
string newpath;
string nowcache;
headers_t meta;
struct stat stbuf;
int nDirType = DIRTYPE_UNKNOWN;
@ -3455,11 +3524,11 @@ static int s3fs_utimens_nocopy(const char *path, const struct timespec ts[2]) {
// Get attributes
if(S_ISDIR(stbuf.st_mode)){
result = chk_dir_object_type(path, strpath, strdel, &meta, &nDirType);
s3_realpath = get_realpath(strdel.c_str());
result = chk_dir_object_type(path, newpath, strpath, nowcache, &meta, &nDirType);
s3_realpath = get_realpath(strpath.c_str());
}else{
strpath = path;
strdel = strpath;
nowcache = strpath;
s3_realpath = get_realpath(strpath.c_str());
result = get_object_attribute(strpath.c_str(), NULL, &meta);
}
@ -3468,27 +3537,20 @@ static int s3fs_utimens_nocopy(const char *path, const struct timespec ts[2]) {
}
if(S_ISDIR(stbuf.st_mode)){
if(DIRTYPE_NEW != nDirType){
// directory object of old version
// Need to remove old dir("dir") and make new dir("dir/")
// Should rebuild all directory object
// Need to remove old dir("dir" etc) and make new dir("dir/")
// At first, remove directory old object
// At first, remove directory old object
if(IS_RMTYPEDIR(nDirType)){
if(0 != (result = curl_delete(s3_realpath.c_str()))){
return result;
}
StatCache::getStatCacheData()->DelStat(strdel);
}
StatCache::getStatCacheData()->DelStat(nowcache);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(strpath.c_str(), stbuf.st_mode, ts[1].tv_sec, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
// directory object of new version
// Over put directory object.
if(0 != (result = create_directory_object(strpath.c_str(), stbuf.st_mode, ts[1].tv_sec, stbuf.st_uid, stbuf.st_gid))){
return result;
}
StatCache::getStatCacheData()->DelStat(strdel);
// Make new directory object("dir/")
if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, ts[1].tv_sec, stbuf.st_uid, stbuf.st_gid))){
return result;
}
}else{
// normal object or directory object of newer version
@ -3529,7 +3591,7 @@ static int s3fs_utimens_nocopy(const char *path, const struct timespec ts[2]) {
if(isclose){
close(fd);
}
StatCache::getStatCacheData()->DelStat(strdel);
StatCache::getStatCacheData()->DelStat(nowcache);
}
return result;

View File

@ -241,10 +241,52 @@ bool S3ObjList::GetNameList(s3obj_list_t& list, bool OnlyNormalized, bool CutSla
return true;
}
typedef std::map<std::string, bool> s3obj_h_t;
bool S3ObjList::MakeHierarchizedList(s3obj_list_t& list, bool haveSlash)
{
s3obj_h_t h_map;
s3obj_h_t::iterator hiter;
s3obj_list_t::const_iterator liter;
for(liter = list.begin(); list.end() != liter; liter++){
string strtmp = (*liter);
if(1 < strtmp.length() && '/' == strtmp[strtmp.length() - 1]){
strtmp = strtmp.substr(0, strtmp.length() - 1);
}
h_map[strtmp] = true;
// check hierarchized directory
for(string::size_type pos = strtmp.find_last_of("/"); string::npos != pos; pos = strtmp.find_last_of("/")){
strtmp = strtmp.substr(0, pos);
if(0 == strtmp.length() || "/" == strtmp){
break;
}
if(h_map.end() == h_map.find(strtmp)){
// not found
h_map[strtmp] = false;
}
}
}
// check map and add lost hierarchized directory.
for(hiter = h_map.begin(); hiter != h_map.end(); ++hiter){
if(false == (*hiter).second){
// add hierarchized directory.
string strtmp = (*hiter).first;
if(haveSlash){
strtmp += "/";
}
list.push_back(strtmp);
}
}
return true;
}
//-------------------------------------------------------------------
// Utility functions for moving objects
//-------------------------------------------------------------------
MVNODE *create_mvnode(const char *old_path, const char *new_path, bool is_dir)
MVNODE *create_mvnode(const char *old_path, const char *new_path, bool is_dir, bool normdir)
{
MVNODE *p;
char *p_old_path;
@ -272,9 +314,10 @@ MVNODE *create_mvnode(const char *old_path, const char *new_path, bool is_dir)
return NULL;
}
p->old_path = p_old_path;
p->new_path = p_new_path;
p->is_dir = is_dir;
p->old_path = p_old_path;
p->new_path = p_new_path;
p->is_dir = is_dir;
p->is_normdir = normdir;
p->prev = NULL;
p->next = NULL;
return p;
@ -283,7 +326,7 @@ MVNODE *create_mvnode(const char *old_path, const char *new_path, bool is_dir)
//
// Add sorted MVNODE data(Ascending order)
//
MVNODE *add_mvnode(MVNODE** head, MVNODE** tail, const char *old_path, const char *new_path, bool is_dir)
MVNODE *add_mvnode(MVNODE** head, MVNODE** tail, const char *old_path, const char *new_path, bool is_dir, bool normdir)
{
if(!head || !tail){
return NULL;
@ -308,7 +351,7 @@ MVNODE *add_mvnode(MVNODE** head, MVNODE** tail, const char *old_path, const cha
// Add into before cur-pos.
// ex: cur("abc"), mvnew("ab")
// ex: cur("abc"), mvnew("abb")
if(NULL == (mvnew = create_mvnode(old_path, new_path, is_dir))){
if(NULL == (mvnew = create_mvnode(old_path, new_path, is_dir, normdir))){
return NULL;
}
if(cur->prev){
@ -325,7 +368,7 @@ MVNODE *add_mvnode(MVNODE** head, MVNODE** tail, const char *old_path, const cha
}
}
// Add into tail.
if(NULL == (mvnew = create_mvnode(old_path, new_path, is_dir))){
if(NULL == (mvnew = create_mvnode(old_path, new_path, is_dir, normdir))){
return NULL;
}
mvnew->prev = (*tail);

View File

@ -51,12 +51,15 @@ class S3ObjList
std::string GetETag(const char* name) const;
bool IsDir(const char* name) const;
bool GetNameList(s3obj_list_t& list, bool OnlyNormalized = true, bool CutSlash = true) const;
static bool MakeHierarchizedList(s3obj_list_t& list, bool haveSlash);
};
typedef struct mvnode {
char *old_path;
char *new_path;
bool is_dir;
bool is_normdir;
struct mvnode *prev;
struct mvnode *next;
} MVNODE;
@ -66,8 +69,8 @@ typedef struct mvnode {
//-------------------------------------------------------------------
std::string get_realpath(const char *path);
MVNODE *create_mvnode(const char *old_path, const char *new_path, bool is_dir);
MVNODE *add_mvnode(MVNODE** head, MVNODE** tail, const char *old_path, const char *new_path, bool is_dir);
MVNODE *create_mvnode(const char *old_path, const char *new_path, bool is_dir, bool normdir = false);
MVNODE *add_mvnode(MVNODE** head, MVNODE** tail, const char *old_path, const char *new_path, bool is_dir, bool normdir = false);
void free_mvnodes(MVNODE *head);
std::string get_username(uid_t uid);