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;
}