static int s3fs_truncate()

in src/s3fs.cpp [2218:2318]


static int s3fs_truncate(const char* _path, off_t size)
{
    WTF8_ENCODE(path)
    int          result;
    headers_t    meta;
    AutoFdEntity autoent;
    FdEntity*    ent = NULL;

    S3FS_PRN_INFO("[path=%s][size=%lld]", path, static_cast<long long>(size));

    if(size < 0){
        size = 0;
    }

    if(0 != (result = check_parent_object_access(path, X_OK))){
        return result;
    }
    if(0 != (result = check_object_access(path, W_OK, NULL))){
        return result;
    }

    // Get file information
    if(0 == (result = get_object_attribute(path, NULL, &meta, true, NULL, false, is_refresh_fakemeta))){
        // File exists

        // [NOTE]
        // If the file exists, the file has already been opened by FUSE before
        // truncate is called. Then the call below will change the file size.
        // (When an already open file is changed the file size, FUSE will not
        // reopen it.)
        // The Flush is called before this file is closed, so there is no need
        // to do it here.
        //
        // [NOTICE]
        // FdManager::Open() ignores changes that reduce the file size for the
        // file you are editing. However, if user opens only onece, edit it,
        // and then shrink the file, it should be done.
        // When this function is called, the file is already open by FUSE or
        // some other operation. Therefore, if the number of open files is 1,
        // no edits other than that fd will be made, and the files will be
        // shrunk using ignore_modify flag even while editing.
        // See the comments when merging this code for FUSE2 limitations.
        // (In FUSE3, it will be possible to handle it reliably using fuse_file_info.)
        //
        bool ignore_modify;
        if(1 < FdManager::GetOpenFdCount(path)){
            ignore_modify = false;
        }else{
            ignore_modify = true;
        }

        if(NULL == (ent = autoent.Open(path, &meta, size, -1, O_RDWR, false, true, ignore_modify, AutoLock::NONE))){
            S3FS_PRN_ERR("could not open file(%s): errno=%d", path, errno);
            return -EIO;
        }

        ent->CheckAndExitDirectReadIfNeeded();
        ent->UpdateCtime();

#if defined(__APPLE__)
        // [NOTE]
        // Only for macos, this truncate calls to "size=0" do not reflect size.
        // The cause is unknown now, but it can be avoided by flushing the file.
        //
        if(0 == size){
            if(0 != (result = ent->Flush(autoent.GetPseudoFd(), true))){
                S3FS_PRN_ERR("could not upload file(%s): result=%d", path, result);
                return result;
            }
            StatCache::getStatCacheData()->DelStat(path);
        }
#endif

    }else{
        // Not found -> Make tmpfile(with size)
        struct fuse_context* pcxt;
        if(NULL == (pcxt = fuse_get_context())){
            return -EIO;
        }
        time_t now = time(NULL);
        meta["Content-Type"]     = std::string("application/octet-stream"); // Static
        meta["x-oss-meta-mode"]  = str(S_IFLNK | S_IRWXU | S_IRWXG | S_IRWXO);
        meta["x-oss-meta-ctime"] = str(now);
        meta["x-oss-meta-mtime"] = str(now);
        meta["x-oss-meta-uid"]   = str(pcxt->uid);
        meta["x-oss-meta-gid"]   = str(pcxt->gid);

        if(NULL == (ent = autoent.Open(path, &meta, size, -1, O_RDWR, true, true, false, AutoLock::NONE))){
            S3FS_PRN_ERR("could not open file(%s): errno=%d", path, errno);
            return -EIO;
        }
        if(0 != (result = ent->Flush(autoent.GetPseudoFd(), true))){
            S3FS_PRN_ERR("could not upload file(%s): result=%d", path, result);
            return result;
        }
        StatCache::getStatCacheData()->DelStat(path);
    }
    S3FS_MALLOCTRIM(0);

    return result;
}