static int s3fs_utimens()

in src/s3fs.cpp [1993:2118]


static int s3fs_utimens(const char* _path, const struct timespec ts[2])
{
    WTF8_ENCODE(path)
    int result;
    std::string strpath;
    std::string newpath;
    std::string nowcache;
    headers_t meta;
    struct stat stbuf;
    dirtype nDirType = DIRTYPE_UNKNOWN;

    S3FS_PRN_INFO("[path=%s][mtime=%lld][ctime/atime=%lld]", path, static_cast<long long>(ts[1].tv_sec), static_cast<long long>(ts[0].tv_sec));

    if(0 == strcmp(path, "/")){
        S3FS_PRN_ERR("Could not change mtime for mount point.");
        return -EIO;
    }
    if(0 != (result = check_parent_object_access(path, X_OK))){
        return result;
    }
    if(0 != (result = check_object_access(path, W_OK, &stbuf))){
        if(0 != check_object_owner(path, &stbuf)){
            return result;
        }
    }

    if(S_ISDIR(stbuf.st_mode)){
        result = chk_dir_object_type(path, newpath, strpath, nowcache, &meta, &nDirType);
    }else{
        strpath  = path;
        nowcache = strpath;
        result   = get_object_attribute(strpath.c_str(), NULL, &meta, true, NULL, false, is_refresh_fakemeta);
    }
    if(0 != result){
        return result;
    }

    //covent u/a/mtime from meta
    struct stat stbuftime;
    StatCache::getStatCacheData()->ToTimeStat(meta, &stbuftime);    
    struct timespec now;
    if(-1 == clock_gettime(static_cast<clockid_t>(CLOCK_REALTIME), &now)){
        abort();
    }

#if __APPLE__
    struct timespec actime = handle_utimens_special_values(ts[0], now, stbuftime.st_ctimespec);
    struct timespec mtime = handle_utimens_special_values(ts[1], now, stbuftime.st_mtimespec);
#else
    struct timespec actime = handle_utimens_special_values(ts[0], now, stbuftime.st_ctim);
    struct timespec mtime = handle_utimens_special_values(ts[1], now, stbuftime.st_mtim);
#endif

    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 = remove_old_type_dir(strpath, nDirType))){
            return result;
        }
        StatCache::getStatCacheData()->DelStat(nowcache);

        // Make new directory object("dir/")
        if(0 != (result = create_directory_object(newpath.c_str(), stbuf.st_mode, actime.tv_sec, mtime.tv_sec, actime.tv_sec, stbuf.st_uid, stbuf.st_gid))){
            return result;
        }
    }else{
        headers_t updatemeta;
        updatemeta["x-oss-meta-mtime"]         = str(mtime);
        updatemeta["x-oss-meta-ctime"]         = str(actime);
        updatemeta["x-oss-meta-atime"]         = str(actime);
        updatemeta["x-oss-copy-source"]        = urlEncode(service_path + S3fsCred::GetBucket() + get_realpath(strpath.c_str()));
        updatemeta["x-oss-metadata-directive"] = "REPLACE";

        // check opened file handle.
        //
        // If the file starts uploading by multipart when the disk capacity is insufficient,
        // we need to put these header after finishing upload.
        // Or if the file is only open, we must update to FdEntity's internal meta.
        //
        AutoFdEntity autoent;
        FdEntity*    ent;
        bool         need_put_header = true;
        bool         keep_mtime      = false;
        if(NULL != (ent = autoent.OpenExistFdEntity(path))){
            if(ent->MergeOrgMeta(updatemeta)){
                // meta is changed, but now uploading.
                // then the meta is pending and accumulated to be put after the upload is complete.
                S3FS_PRN_INFO("meta pending until upload is complete");
                need_put_header = false;
                ent->SetHoldingMtime(mtime);

                // If there is data in the Stats cache, update the Stats cache.
                StatCache::getStatCacheData()->UpdateMetaStats(strpath, updatemeta);

            }else{
                S3FS_PRN_INFO("meta is not pending, but need to keep current mtime.");

                // [NOTE]
                // Depending on the order in which write/flush and utimens are called,
                // the mtime updated here may be overwritten at the time of flush.
                // To avoid that, set a special flag.
                //
                keep_mtime = true;
            }
        }
        if(need_put_header){
            // not found opened file.
            merge_headers(meta, updatemeta, true);

            // upload meta directly.
            if(0 != (result = put_headers(strpath.c_str(), meta, true))){
                return result;
            }
            StatCache::getStatCacheData()->DelStat(nowcache);

            if(keep_mtime){
                ent->SetHoldingMtime(mtime);
            }
        }
    }
    S3FS_MALLOCTRIM(0);

    return 0;
}