static int get_object_attribute()

in src/s3fs.cpp [345:493]


static int get_object_attribute(const char* path, struct stat* pstbuf, headers_t* pmeta, bool overcheck, bool* pisforce, bool add_no_truncate_cache, bool refresh_fakemeta)
{
    int          result = -1;
    struct stat  tmpstbuf;
    struct stat* pstat = pstbuf ? pstbuf : &tmpstbuf;
    headers_t    tmpHead;
    headers_t*   pheader = pmeta ? pmeta : &tmpHead;
    std::string  strpath;
    S3fsCurl     s3fscurl;
    bool         forcedir = false;
    bool         fakemeta = false;
    std::string::size_type Pos;

    S3FS_PRN_DBG("[path=%s]", path);

    if(!path || '\0' == path[0]){
        return -ENOENT;
    }

    memset(pstat, 0, sizeof(struct stat));
    if(0 == strcmp(path, "/") || 0 == strcmp(path, ".")){
        pstat->st_nlink = 1; // see fuse faq
        pstat->st_mode  = mp_mode;
        pstat->st_uid   = is_s3fs_uid ? s3fs_uid : mp_uid;
        pstat->st_gid   = is_s3fs_gid ? s3fs_gid : mp_gid;
        return 0;
    }

    // Check cache.
    pisforce    = (NULL != pisforce ? pisforce : &forcedir);
    (*pisforce) = false;
    strpath     = path;
    if(support_compat_dir && overcheck && std::string::npos != (Pos = strpath.find("_$folder$", 0))){
        strpath.erase(Pos);
        strpath += "/";
    }
    if(StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck, pisforce, &fakemeta)){
        if (refresh_fakemeta && fakemeta) {
            // igrone the fake meta
        } else {
            return 0;
        }
    }
    if(StatCache::getStatCacheData()->IsNoObjectCache(strpath)){
        // there is the path in the cache for no object, it is no object.
        return -ENOENT;
    }

    // At first, check path
    strpath     = path;
    result      = s3fscurl.HeadRequest(strpath.c_str(), (*pheader));
    s3fscurl.DestroyCurlHandle();

    // if not found target path object, do over checking
   if(0 != result){
        if(overcheck){
            // when support_compat_dir is disabled, strpath maybe have "_$folder$".
            if('/' != *strpath.rbegin() && std::string::npos == strpath.find("_$folder$", 0)){
                // now path is "object", do check "object/" for over checking
                strpath    += "/";
                result      = s3fscurl.HeadRequest(strpath.c_str(), (*pheader));
                s3fscurl.DestroyCurlHandle();
            }
            if(support_compat_dir && 0 != result){
                // now path is "object/", do check "object_$folder$" for over checking
                strpath.erase(strpath.length() - 1);
                strpath    += "_$folder$";
                result      = s3fscurl.HeadRequest(strpath.c_str(), (*pheader));
                s3fscurl.DestroyCurlHandle();

              if(0 != result){
                  // cut "_$folder$" for over checking "no dir object" after here
                  if(std::string::npos != (Pos = strpath.find("_$folder$", 0))){
                      strpath.erase(Pos);
                  }
              }
            }
        }
        if(support_compat_dir && 0 != result && std::string::npos == strpath.find("_$folder$", 0)){
            // now path is "object" or "object/", do check "no dir object" which is not object but has only children.
            if('/' == *strpath.rbegin()){
                strpath.erase(strpath.length() - 1);
            }
            if(-ENOTEMPTY == directory_empty(strpath.c_str())){
                // found "no dir object".
                strpath  += "/";
                *pisforce = true;
                result    = 0;
            }
        }
    }else{
        if(support_compat_dir && '/' != *strpath.rbegin() && std::string::npos == strpath.find("_$folder$", 0) && is_need_check_obj_detail(*pheader)){
            // check a case of that "object" does not have attribute and "object" is possible to be directory.
            if(-ENOTEMPTY == directory_empty(strpath.c_str())){
                // found "no dir object".
                strpath  += "/";
                *pisforce = true;
                result    = 0;
            }
        }
    }

    // [NOTE]
    // If the file is listed but not allowed access, put it in
    // the positive cache instead of the negative cache.
    // 
    if(0 != result){
        // finally, "path" object did not find. Add no object cache.
        strpath = path;  // reset original
        StatCache::getStatCacheData()->AddNoObjectCache(strpath);
        return result;
    }

    // if path has "_$folder$", need to cut it.
    if(std::string::npos != (Pos = strpath.find("_$folder$", 0))){
        strpath.erase(Pos);
        strpath += "/";
    }

    // Set into cache
    //
    // [NOTE]
    // When add_no_truncate_cache is true, the stats is always cached.
    // This cached stats is only removed by DelStat().
    // This is necessary for the case to access the attribute of opened file.
    // (ex. getxattr() is called while writing to the opened file.)
    //
    if(add_no_truncate_cache || 0 != StatCache::getStatCacheData()->GetCacheSize()){
        // add into stat cache
        if(!StatCache::getStatCacheData()->AddStat(strpath, (*pheader), forcedir, add_no_truncate_cache)){
            S3FS_PRN_ERR("failed adding stat cache [path=%s]", strpath.c_str());
            return -ENOENT;
        }
        if(!StatCache::getStatCacheData()->GetStat(strpath, pstat, pheader, overcheck, pisforce)){
            // There is not in cache.(why?) -> retry to convert.
            if(!StatCache::getStatCacheData()->ConvertMetaToStat(strpath, (*pheader), pstat, forcedir)){
                S3FS_PRN_ERR("failed convert headers to stat[path=%s]", strpath.c_str());
                return -ENOENT;
            }
        }
    }else{
        // cache size is Zero -> only convert.
        if(!StatCache::getStatCacheData()->ConvertMetaToStat(strpath, (*pheader), pstat, forcedir)){
            S3FS_PRN_ERR("failed convert headers to stat[path=%s]", strpath.c_str());
            return -ENOENT;
        }
    }
    return 0;
}