1 /*
2 * Copyright (c) 2024 Huawei Device Co., Ltd.
3 * Licensed under the Apache License, Version 2.0 (the "License");
4 * you may not use this file except in compliance with the License.
5 * You may obtain a copy of the License at
6 *
7 * http://www.apache.org/licenses/LICENSE-2.0
8 *
9 * Unless required by applicable law or agreed to in writing, software
10 * distributed under the License is distributed on an "AS IS" BASIS,
11 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 * See the License for the specific language governing permissions and
13 * limitations under the License.
14 */
15 #include "file_operations_cloud.h"
16
17 #include <cerrno>
18 #include <sstream>
19 #include <sys/types.h>
20 #include <sys/xattr.h>
21 #include <functional>
22
23 #include "account_status.h"
24 #include "cloud_disk_inode.h"
25 #include "cloud_file_fault_event.h"
26 #include "cloud_file_kit.h"
27 #include "cloud_file_utils.h"
28 #include "clouddisk_rdb_transaction.h"
29 #include "clouddisk_rdb_utils.h"
30 #include "clouddisk_notify.h"
31 #include "database_manager.h"
32 #include "directory_ex.h"
33 #include "ffrt_inner.h"
34 #include "parameter.h"
35 #include "parameters.h"
36 #include "file_operations_helper.h"
37 #include "fuse_ioctl.h"
38 #include "hitrace_meter.h"
39 #include "securec.h"
40 #include "utils_log.h"
41
42 namespace OHOS {
43 namespace FileManagement {
44 namespace CloudDisk {
45 using namespace std;
46 using namespace CloudFile;
47 enum XATTR_CODE {
48 ERROR_CODE = -1,
49 HMDFS_PERMISSION,
50 CLOUD_LOCATION,
51 CLOUD_RECYCLE,
52 IS_FAVORITE,
53 HAS_THM
54 };
55 namespace {
56 static const uint32_t STAT_NLINK_REG = 1;
57 static const uint32_t STAT_NLINK_DIR = 2;
58 static const uint32_t CLOUD_FILE_LAYER = 2;
59 static const uint32_t USER_LOCAL_ID_OFFSET = 100;
60 static const uint32_t STAT_MODE_REG = 0660;
61 static const uint32_t STAT_MODE_DIR = 0771;
62 static const uint32_t MILLISECOND_TO_SECONDS_TIMES = 1000;
63 static const uint32_t RECYCLE_LOCAL_ID = 4;
64 static const string FILE_LOCAL = "1";
65 static const string ROOT_CLOUD_ID = "rootId";
66 static const string RECYCLE_NAME = ".trash";
67 static const uint64_t UNKNOWN_INODE_ID = 0;
68 static const std::string FILEMANAGER_KEY = "persist.kernel.bundle_name.filemanager";
69 static const string LOCAL_PATH_DATA_STORAGE = "/data/storage/el2/cloud/";
70 static const unsigned int MAX_READ_SIZE = 4 * 1024 * 1024;
71 static const unsigned int CATCH_TIMEOUT_S = 4;
72 static const std::chrono::seconds READ_TIMEOUT_S = 16s;
73 static const std::chrono::seconds OPEN_TIMEOUT_S = 4s;
74 }
75
76 const int32_t MAX_SIZE = 4096;
77
78 struct CloudDiskCopy {
79 char destPath[MAX_SIZE];
80 };
81
fuse_inval(fuse_session * se,fuse_ino_t parentIno,fuse_ino_t childIno,const string & childName)82 static void fuse_inval(fuse_session *se, fuse_ino_t parentIno, fuse_ino_t childIno, const string &childName)
83 {
84 auto task = [se, parentIno, childIno, childName] {
85 if (fuse_lowlevel_notify_inval_entry(se, parentIno, childName.c_str(), childName.size())) {
86 fuse_lowlevel_notify_inval_inode(se, childIno, 0, 0);
87 }
88 };
89 ffrt::submit(task, {}, {}, ffrt::task_attr().qos(ffrt_qos_background));
90 }
91
InitInodeAttr(struct CloudDiskFuseData * data,fuse_ino_t parent,struct CloudDiskInode * childInode,const MetaBase & metaBase,const int64_t & inodeId)92 static void InitInodeAttr(struct CloudDiskFuseData *data, fuse_ino_t parent,
93 struct CloudDiskInode *childInode, const MetaBase &metaBase, const int64_t &inodeId)
94 {
95 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
96 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
97 static_cast<int64_t>(parent));
98 if (parentInode == nullptr) {
99 LOGE("parent inode not found");
100 return;
101 }
102 childInode->stat = parentInode->stat;
103 childInode->stat.st_ino = static_cast<uint64_t>(inodeId);
104 childInode->stat.st_mtime = metaBase.mtime / MILLISECOND_TO_SECONDS_TIMES;
105 childInode->stat.st_atime = metaBase.atime / MILLISECOND_TO_SECONDS_TIMES;
106
107 childInode->bundleName = parentInode->bundleName;
108 childInode->fileName = metaBase.name;
109 childInode->layer = FileOperationsHelper::GetNextLayer(parentInode, parent);
110 childInode->parent = parent;
111 childInode->cloudId = metaBase.cloudId;
112 childInode->ops = make_shared<FileOperationsCloud>();
113
114 if (S_ISDIR(metaBase.mode)) {
115 childInode->stat.st_mode = S_IFDIR | STAT_MODE_DIR;
116 childInode->stat.st_nlink = STAT_NLINK_DIR;
117 } else {
118 childInode->stat.st_mode = S_IFREG | STAT_MODE_REG;
119 childInode->stat.st_nlink = STAT_NLINK_REG;
120 childInode->stat.st_size = metaBase.size;
121 }
122 }
123
InitFileAttr(struct CloudDiskFuseData * data,struct fuse_file_info * fi)124 static shared_ptr<CloudDiskFile> InitFileAttr(struct CloudDiskFuseData *data, struct fuse_file_info *fi)
125 {
126 std::unique_lock<std::shared_mutex> wLock(data->fileLock, std::defer_lock);
127 shared_ptr<CloudDiskFile> filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
128 if (filePtr == nullptr) {
129 filePtr = make_shared<CloudDiskFile>();
130 wLock.lock();
131 data->fileCache[fi->fh] = filePtr;
132 wLock.unlock();
133 }
134 filePtr->refCount++;
135 return filePtr;
136 }
137
InitLocalIdCache(struct CloudDiskFuseData * data,const std::string & key,const int64_t val)138 static void InitLocalIdCache(struct CloudDiskFuseData *data, const std::string &key, const int64_t val)
139 {
140 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
141 std::unique_lock<std::shared_mutex> wLock(data->localIdLock, std::defer_lock);
142 int64_t localId = FileOperationsHelper::FindLocalId(data, key);
143 if (localId == -1) {
144 wLock.lock();
145 data->localIdCache[key] = val;
146 wLock.unlock();
147 }
148 }
149
LookUpRecycleBin(struct CloudDiskFuseData * data,fuse_ino_t parent,shared_ptr<CloudDiskInode> parentInode,struct fuse_entry_param * e)150 static void LookUpRecycleBin(struct CloudDiskFuseData *data, fuse_ino_t parent,
151 shared_ptr<CloudDiskInode> parentInode, struct fuse_entry_param *e)
152 {
153 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
154 std::unique_lock<std::shared_mutex> cacheWLock(data->cacheLock, std::defer_lock);
155 auto child = FileOperationsHelper::FindCloudDiskInode(data, RECYCLE_LOCAL_ID);
156 if (child == nullptr) {
157 child = make_shared<CloudDiskInode>();
158 child->stat = parentInode->stat;
159 child->stat.st_ino = RECYCLE_LOCAL_ID;
160 child->bundleName = parentInode->bundleName;
161 child->fileName = RECYCLE_NAME;
162 child->layer = FileOperationsHelper::GetNextLayer(parentInode, parent);
163 child->parent = parent;
164 child->cloudId = RECYCLE_CLOUD_ID;
165 child->ops = make_shared<FileOperationsCloud>();
166 child->stat.st_mode = S_IFDIR | STAT_MODE_DIR;
167 child->stat.st_nlink = STAT_NLINK_DIR;
168 cacheWLock.lock();
169 data->inodeCache[RECYCLE_LOCAL_ID] = child;
170 cacheWLock.unlock();
171 }
172 e->ino = static_cast<fuse_ino_t>(RECYCLE_LOCAL_ID);
173 FileOperationsHelper::GetInodeAttr(child, &e->attr);
174 }
175
UpdateChildCache(struct CloudDiskFuseData * data,int64_t localId,shared_ptr<CloudDiskInode> child)176 static shared_ptr<CloudDiskInode> UpdateChildCache(struct CloudDiskFuseData *data, int64_t localId,
177 shared_ptr<CloudDiskInode> child)
178 {
179 std::unique_lock<std::shared_mutex> cacheWLock(data->cacheLock, std::defer_lock);
180 std::unique_lock<std::shared_mutex> localIdWLock(data->localIdLock, std::defer_lock);
181 if (child == nullptr) {
182 child = make_shared<CloudDiskInode>();
183 cacheWLock.lock();
184 data->inodeCache[localId] = child;
185 cacheWLock.unlock();
186 } else {
187 auto old_key = std::to_string(child->parent) + child->fileName;
188 localIdWLock.lock();
189 data->localIdCache.erase(old_key);
190 localIdWLock.unlock();
191 }
192 return child;
193 }
194
LookupRecycledFile(struct CloudDiskFuseData * data,const char * name,const std::string bundleName,struct fuse_entry_param * e)195 static int32_t LookupRecycledFile(struct CloudDiskFuseData *data, const char *name,
196 const std::string bundleName, struct fuse_entry_param *e)
197 {
198 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
199 MetaBase metaBase(name);
200 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId, bundleName,
201 RECYCLE_CLOUD_ID);
202 int ret = metaFile->DoLookup(metaBase);
203 if (ret != 0) {
204 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::LOOKUP,
205 CloudFile::FaultType::FILE, ret, "file " + GetAnonyString(name) + " not found in recyclebin"});
206 return ret;
207 }
208 int64_t inodeId = static_cast<int64_t>(CloudFileUtils::DentryHash(metaBase.cloudId));
209 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, inodeId);
210 if (inoPtr == nullptr) {
211 string nameStr = name;
212 size_t lastSlash = nameStr.find_last_of("_");
213 metaBase.name = nameStr.substr(0, lastSlash);
214 inoPtr = UpdateChildCache(data, inodeId, inoPtr);
215 inoPtr->refCount++;
216 InitInodeAttr(data, RECYCLE_LOCAL_ID, inoPtr.get(), metaBase, inodeId);
217 inoPtr->parent = UNKNOWN_INODE_ID;
218 }
219 e->ino = static_cast<fuse_ino_t>(inodeId);
220 FileOperationsHelper::GetInodeAttr(inoPtr, &e->attr);
221 return 0;
222 }
223
DoCloudLookup(fuse_req_t req,fuse_ino_t parent,const char * name,struct fuse_entry_param * e)224 static int32_t DoCloudLookup(fuse_req_t req, fuse_ino_t parent, const char *name,
225 struct fuse_entry_param *e)
226 {
227 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
228 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
229 if (parent == FUSE_ROOT_ID) {
230 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::LOOKUP,
231 CloudFile::FaultType::WARNING, EINVAL, "cloud file operations should not get a fuse root inode"});
232 return EINVAL;
233 }
234
235 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
236 static_cast<int64_t>(parent));
237 if (parentInode == nullptr) {
238 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::LOOKUP,
239 CloudFile::FaultType::INODE_FILE, EINVAL, "fail to find parent inode"});
240 return EINVAL;
241 }
242 if (name == RECYCLE_NAME) {
243 LookUpRecycleBin(data, parent, parentInode, e);
244 return 0;
245 } else if (parent == RECYCLE_LOCAL_ID) {
246 int32_t ret = LookupRecycledFile(data, name, parentInode->bundleName, e);
247 if (ret != 0) {
248 LOGE("fail to lookup recycledfile");
249 return ret;
250 }
251 return 0;
252 }
253 MetaBase metaBase(name);
254 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId, parentInode->bundleName,
255 parentInode->cloudId);
256 int32_t ret = metaFile->DoLookup(metaBase);
257 if (ret != 0) {
258 LOGE("lookup dentry failed, name:%{public}s, ret = %{public}d", GetAnonyString(name).c_str(), ret);
259 return ENOENT;
260 }
261 string key = std::to_string(parent) + name;
262 int64_t inodeId = static_cast<int64_t>(CloudFileUtils::DentryHash(metaBase.cloudId));
263 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, inodeId);
264 // if inoPtr is nullptr, UpdateChildCache will create it
265 auto child = UpdateChildCache(data, inodeId, inoPtr);
266 child->refCount++;
267 InitInodeAttr(data, parent, child.get(), metaBase, inodeId);
268 InitLocalIdCache(data, key, inodeId);
269 e->ino = static_cast<fuse_ino_t>(inodeId);
270 FileOperationsHelper::GetInodeAttr(child, &e->attr);
271 return 0;
272 }
273
Lookup(fuse_req_t req,fuse_ino_t parent,const char * name)274 void FileOperationsCloud::Lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
275 {
276 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
277 struct fuse_entry_param e;
278 e.attr_timeout = 1.0;
279 e.entry_timeout = 1.0;
280 int32_t err = DoCloudLookup(req, parent, name, &e);
281 if (err) {
282 fuse_reply_err(req, err);
283 } else {
284 fuse_reply_entry(req, &e);
285 }
286 }
287
Access(fuse_req_t req,fuse_ino_t ino,int mask)288 void FileOperationsCloud::Access(fuse_req_t req, fuse_ino_t ino, int mask)
289 {
290 LOGI("Access operation is not supported!");
291 fuse_reply_err(req, ENOSYS);
292 }
293
GetAttr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)294 void FileOperationsCloud::GetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
295 {
296 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
297 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
298 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
299 if (inoPtr == nullptr) {
300 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETATTR,
301 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
302 fuse_reply_err(req, EINVAL);
303 return;
304 }
305 fuse_reply_attr(req, &inoPtr->stat, 0);
306 }
307
HandleCloudError(fuse_req_t req,CloudError error)308 static int32_t HandleCloudError(fuse_req_t req, CloudError error)
309 {
310 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
311 int32_t ret = 0;
312 switch (error) {
313 case CloudError::CK_NO_ERROR:
314 ret = 0;
315 break;
316 case CloudError::CK_NETWORK_ERROR:
317 ret = ENOTCONN;
318 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
319 CloudFile::FaultType::WARNING, ENOTCONN, "network error"});
320 break;
321 case CloudError::CK_SERVER_ERROR:
322 ret = EIO;
323 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
324 CloudFile::FaultType::WARNING, EIO, "server error"});
325 break;
326 case CloudError::CK_LOCAL_ERROR:
327 ret = EINVAL;
328 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
329 CloudFile::FaultType::WARNING, EINVAL, "local error"});
330 break;
331 default:
332 ret = EIO;
333 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::SESSION,
334 CloudFile::FaultType::WARNING, EIO, "unknown error"});
335 break;
336 }
337 return ret;
338 }
339
GetDatabase(int32_t userId,const string & bundleName)340 static shared_ptr<CloudDatabase> GetDatabase(int32_t userId, const string &bundleName)
341 {
342 auto instance = CloudFile::CloudFileKit::GetInstance();
343 if (instance == nullptr) {
344 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::OPEN,
345 CloudFile::FaultType::DRIVERKIT, EINVAL, "get cloud file helper instance failed"});
346 return nullptr;
347 }
348
349 if (AccountStatus::IsNeedCleanCache()) {
350 auto ret = instance->CleanCloudUserInfo(userId);
351 if (ret != 0) {
352 return nullptr;
353 }
354 LOGI("execute clean cloud user info success");
355 }
356
357 auto database = instance->GetCloudDatabase(userId, bundleName);
358 if (database == nullptr) {
359 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READ,
360 CloudFile::FaultType::QUERY_DATABASE, EINVAL, "get cloud file kit database fail"});
361 return nullptr;
362 }
363 return database;
364 }
365
GetFileOpenFlags(int32_t fileFlags)366 static unsigned int GetFileOpenFlags(int32_t fileFlags)
367 {
368 unsigned int flags = static_cast<unsigned int>(fileFlags);
369 if ((flags & O_ACCMODE) & O_WRONLY) {
370 flags &= ~O_WRONLY;
371 flags |= O_RDWR;
372 }
373 if (flags & O_APPEND) {
374 flags &= ~O_APPEND;
375 }
376 if (flags & O_DIRECT) {
377 flags &= ~O_DIRECT;
378 }
379 return flags;
380 }
381
CheckBucketPath(string cloudId,string bundleName,int32_t userId,string tmpPath)382 static int32_t CheckBucketPath(string cloudId, string bundleName, int32_t userId, string tmpPath)
383 {
384 string baseDir = CloudFileUtils::GetLocalBaseDir(bundleName, userId);
385 string bucketPath = CloudFileUtils::GetLocalBucketPath(cloudId, bundleName, userId);
386 if (access(baseDir.c_str(), F_OK) != 0) {
387 LOGE("bucket path's parent directory not exits, errno=%{public}d", errno);
388 auto accessErrno = errno;
389 if (unlink(tmpPath.c_str()) != 0) {
390 LOGE("unlink tmpPath failed, errno=%{public}d", errno);
391 return errno;
392 }
393 return accessErrno;
394 }
395 if (access(bucketPath.c_str(), F_OK) != 0) {
396 if (mkdir(bucketPath.c_str(), STAT_MODE_DIR) != 0) {
397 LOGE("create bucket path directory failed, errno=%{public}d", errno);
398 auto mkdirErrno = errno;
399 if (unlink(tmpPath.c_str()) != 0) {
400 LOGE("unlink tmpPath failed, errno=%{public}d", errno);
401 return errno;
402 }
403 return mkdirErrno;
404 }
405 LOGW("mkdir bucketPath success");
406 }
407 return EOK;
408 }
409
HandleCloudOpenSuccess(struct fuse_file_info * fi,struct CloudDiskFuseData * data,shared_ptr<CloudDiskInode> inoPtr,CloudOpenParams cloudOpenParams)410 static int32_t HandleCloudOpenSuccess(struct fuse_file_info *fi, struct CloudDiskFuseData *data,
411 shared_ptr<CloudDiskInode> inoPtr, CloudOpenParams cloudOpenParams)
412 {
413 auto metaBase = cloudOpenParams.metaBase;
414 auto metaFile = cloudOpenParams.metaFile;
415 auto filePtr = cloudOpenParams.filePtr;
416 if (metaBase.fileType != FILE_TYPE_CONTENT) {
417 string path = CloudFileUtils::GetLocalFilePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
418 string tmpPath = CloudFileUtils::GetLocalDKCachePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
419 auto ret = CheckBucketPath(inoPtr->cloudId, inoPtr->bundleName, data->userId, tmpPath);
420 if (ret != EOK) {
421 LOGE("check bucketPath failed, ret = %{public}d", ret);
422 return ret;
423 }
424 if (access(path.c_str(), F_OK) != 0) {
425 ret = rename(tmpPath.c_str(), path.c_str());
426 if (ret == EOK) {
427 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
428 auto rdbstore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
429 rdbstore->UpdateTHMStatus(metaFile, metaBase, CloudSync::DOWNLOADED_THM);
430 } else {
431 LOGE("path rename failed, tmpPath:%{public}s, errno:%{public}d",
432 GetAnonyString(tmpPath).c_str(), errno);
433 return errno;
434 }
435 }
436 unsigned int flags = GetFileOpenFlags(fi->flags);
437 int32_t fd = open(path.c_str(), flags);
438 if (fd < 0) {
439 LOGE("failed to open local file, errno: %{public}d", errno);
440 return errno;
441 }
442 filePtr->type = CLOUD_DISK_FILE_TYPE_LOCAL;
443 filePtr->fd = fd;
444 } else {
445 filePtr->type = CLOUD_DISK_FILE_TYPE_CLOUD;
446 }
447 return EOK;
448 }
449
DoSessionInit(shared_ptr<CloudDiskFile> filePtr,shared_ptr<CloudError> error,shared_ptr<bool> openFinish,shared_ptr<ffrt::condition_variable> cond,CloudOpenParams cloudOpenParams)450 static void DoSessionInit(shared_ptr<CloudDiskFile> filePtr, shared_ptr<CloudError> error,
451 shared_ptr<bool> openFinish, shared_ptr<ffrt::condition_variable> cond, CloudOpenParams cloudOpenParams)
452 {
453 ffrt::submit([filePtr, error, openFinish, cond, cloudOpenParams] {
454 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
455 auto session = filePtr->readSession;
456 if (!session) {
457 LOGE("readSession is nullptr");
458 {
459 unique_lock lck(filePtr->openLock);
460 *openFinish = true;
461 }
462 cond->notify_one();
463 *error = CloudError::CK_LOCAL_ERROR;
464 return;
465 }
466 *error = session->InitSession();
467 if (*error == CloudError::CK_NO_ERROR) {
468 if (cloudOpenParams.metaBase.fileType != FILE_TYPE_CONTENT) {
469 session->Catch(*error, CATCH_TIMEOUT_S);
470 }
471 }
472 {
473 unique_lock lck(filePtr->openLock);
474 *openFinish = true;
475 }
476 cond->notify_one();
477 LOGI("download done");
478 return;
479 });
480 }
481
DoCloudOpen(fuse_req_t req,struct fuse_file_info * fi,shared_ptr<CloudDiskInode> inoPtr,struct CloudDiskFuseData * data,CloudOpenParams cloudOpenParams)482 static int32_t DoCloudOpen(fuse_req_t req, struct fuse_file_info *fi,
483 shared_ptr<CloudDiskInode> inoPtr, struct CloudDiskFuseData *data, CloudOpenParams cloudOpenParams)
484 {
485 auto error = make_shared<CloudError>();
486 auto openFinish = make_shared<bool>(false);
487 auto cond = make_shared<ffrt::condition_variable>();
488 auto filePtr = cloudOpenParams.filePtr;
489 DoSessionInit(filePtr, error, openFinish, cond, cloudOpenParams);
490 unique_lock lck(filePtr->openLock);
491 auto waitStatus = cond->wait_for(lck, OPEN_TIMEOUT_S, [openFinish] {
492 return *openFinish;
493 });
494 if (!waitStatus) {
495 LOGE("init session timeout");
496 return ENETUNREACH;
497 }
498 auto ret = HandleCloudError(req, *error);
499 if (!ret) {
500 auto cloudOpenRet = HandleCloudOpenSuccess(fi, data, inoPtr, cloudOpenParams);
501 if (cloudOpenRet) {
502 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName, CloudFile::FaultOperation::OPEN,
503 CloudFile::FaultType::FILE, cloudOpenRet, "cloud open failed"});
504 return cloudOpenRet;
505 }
506 return 0;
507 } else {
508 LOGE("cloud open failed");
509 return ret;
510 }
511 }
512
ErasePathCache(string path,CloudDiskFuseData * data)513 static void ErasePathCache(string path, CloudDiskFuseData *data)
514 {
515 if (data->readSessionCache.find(path) != data->readSessionCache.end()) {
516 data->readSessionCache.erase(path);
517 }
518 }
519
HandleNewSession(struct CloudDiskFuseData * data,const struct SessionCountParams & sessionParam,shared_ptr<CloudDiskFile> filePtr,shared_ptr<CloudDatabase> database)520 static void HandleNewSession(struct CloudDiskFuseData *data, const struct SessionCountParams &sessionParam,
521 shared_ptr<CloudDiskFile> filePtr, shared_ptr<CloudDatabase> database)
522 {
523 string path = sessionParam.path;
524 if (data->readSessionCache.find(path) != data->readSessionCache.end()) {
525 filePtr->readSession = data->readSessionCache[path];
526 return;
527 }
528 filePtr->readSession = database->NewAssetReadSession(data->userId, "file",
529 sessionParam.cloudId, sessionParam.assets, path);
530 if (filePtr->readSession) {
531 data->readSessionCache[path] = filePtr->readSession;
532 }
533 }
534
GetNewSession(shared_ptr<CloudDiskInode> inoPtr,string & path,struct CloudDiskFuseData * data,shared_ptr<CloudDatabase> database,CloudOpenParams cloudOpenParams)535 static int32_t GetNewSession(shared_ptr<CloudDiskInode> inoPtr,
536 string &path, struct CloudDiskFuseData *data, shared_ptr<CloudDatabase> database,
537 CloudOpenParams cloudOpenParams)
538 {
539 string cloudId = inoPtr->cloudId;
540 string assets = "content";
541 auto metaBase = cloudOpenParams.metaBase;
542 auto filePtr = cloudOpenParams.filePtr;
543 if (metaBase.fileType == FILE_TYPE_THUMBNAIL ||
544 metaBase.fileType == FILE_TYPE_LCD) {
545 assets = (metaBase.fileType == FILE_TYPE_THUMBNAIL) ? "thumbnail" : "lcd";
546 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
547 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
548 auto ret = rdbStore->GetSrcCloudId(inoPtr->cloudId, cloudId);
549 if (ret) {
550 LOGE("get %{public}s cloudId failed", assets.c_str());
551 return ret;
552 }
553 }
554 LOGD("cloudId %s", cloudId.c_str());
555 struct SessionCountParams sessionParam = {path, cloudId, assets};
556 HandleNewSession(data, sessionParam, filePtr, database);
557 return EOK;
558 }
559
HandleOpenFail(HandleOpenErrorParams params,string path,CloudDiskFuseData * data,fuse_file_info * fi)560 static void HandleOpenFail(HandleOpenErrorParams params, string path, CloudDiskFuseData *data,
561 fuse_file_info *fi)
562 {
563 ErasePathCache(path, data);
564 params.filePtr->readSession = nullptr;
565 FileOperationsHelper::PutCloudDiskFile(data, params.filePtr, fi->fh);
566 fuse_inval(data->se, params.inoPtr->parent, params.ino, params.inoPtr->fileName);
567 }
568
HandleSessionNull(HandleOpenErrorParams params,CloudDiskFuseData * data,fuse_file_info * fi)569 static void HandleSessionNull(HandleOpenErrorParams params, CloudDiskFuseData *data,
570 fuse_file_info *fi)
571 {
572 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::OPEN,
573 CloudFile::FaultType::DRIVERKIT, EPERM, "readSession is null"});
574 FileOperationsHelper::PutCloudDiskFile(data, params.filePtr, fi->fh);
575 fuse_inval(data->se, params.inoPtr->parent, params.ino, params.inoPtr->fileName);
576 }
577
HandleCloudReopen(struct fuse_file_info * fi,struct CloudDiskFuseData * data,shared_ptr<CloudDiskInode> inoPtr,CloudOpenParams cloudOpenParams,fuse_req_t req)578 static void HandleCloudReopen(struct fuse_file_info *fi, struct CloudDiskFuseData *data,
579 shared_ptr<CloudDiskInode> inoPtr, CloudOpenParams cloudOpenParams, fuse_req_t req)
580 {
581 auto metaBase = cloudOpenParams.metaBase;
582 auto filePtr = cloudOpenParams.filePtr;
583 if (metaBase.fileType != FILE_TYPE_CONTENT) {
584 string path = CloudFileUtils::GetLocalFilePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
585 unsigned int flags = GetFileOpenFlags(fi->flags);
586 int32_t fd = open(path.c_str(), flags);
587 if (fd < 0) {
588 LOGE("failed to open local file, errno: %{public}d", errno);
589 fuse_reply_err(req, errno);
590 return;
591 }
592 filePtr->type = CLOUD_DISK_FILE_TYPE_LOCAL;
593 filePtr->fd = fd;
594 } else {
595 filePtr->type = CLOUD_DISK_FILE_TYPE_CLOUD;
596 filePtr->readSession->sessionCount++;
597 }
598 fuse_reply_open(req, fi);
599 }
600
CloudOpen(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr,struct fuse_file_info * fi,string path,fuse_ino_t ino)601 static void CloudOpen(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr,
602 struct fuse_file_info *fi, string path, fuse_ino_t ino)
603 {
604 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
605 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
606 auto database = GetDatabase(data->userId, inoPtr->bundleName);
607 if (!database) {
608 LOGE("database is null");
609 fuse_inval(data->se, inoPtr->parent, ino, inoPtr->fileName);
610 return (void) fuse_reply_err(req, EPERM);
611 }
612 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(inoPtr->parent));
613 if (parentInode == nullptr) {
614 LOGE("parent inode not found");
615 fuse_inval(data->se, inoPtr->parent, ino, inoPtr->fileName);
616 return (void) fuse_reply_err(req, EPERM);
617 }
618 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
619 parentInode->bundleName, parentInode->cloudId);
620 MetaBase metaBase(inoPtr->fileName);
621 auto ret = metaFile->DoLookup(metaBase);
622 if (ret != EOK) {
623 fuse_inval(data->se, inoPtr->parent, ino, inoPtr->fileName);
624 return (void) fuse_reply_err(req, EPERM);
625 }
626 auto filePtr = InitFileAttr(data, fi);
627 CloudOpenParams cloudOpenParams = {metaBase, metaFile, filePtr};
628 std::unique_lock<std::shared_mutex> lck(inoPtr->sessionLock);
629 if (GetNewSession(inoPtr, path, data, database, cloudOpenParams)) {
630 FileOperationsHelper::PutCloudDiskFile(data, filePtr, fi->fh);
631 fuse_inval(data->se, inoPtr->parent, ino, inoPtr->fileName);
632 return (void) fuse_reply_err(req, EPERM);
633 }
634 HandleOpenErrorParams handleOpenErrorParams = {filePtr, inoPtr, ino};
635 if (filePtr->readSession) {
636 if (filePtr->readSession->sessionCount > 0) {
637 return HandleCloudReopen(fi, data, inoPtr, cloudOpenParams, req);
638 }
639 auto ret = DoCloudOpen(req, fi, inoPtr, data, cloudOpenParams);
640 if (!ret) {
641 filePtr->readSession->sessionCount++;
642 fuse_reply_open(req, fi);
643 } else {
644 HandleOpenFail(handleOpenErrorParams, path, data, fi);
645 return (void) fuse_reply_err(req, ret);
646 }
647 } else {
648 HandleSessionNull(handleOpenErrorParams, data, fi);
649 return (void) fuse_reply_err(req, EPERM);
650 }
651 }
652
Open(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)653 void FileOperationsCloud::Open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
654 {
655 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
656 LOGE("wait move error");
657 return (void) fuse_reply_err(req, EBUSY);
658 }
659 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
660 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
661 std::unique_lock<std::shared_mutex> wLock(data->fileIdLock, std::defer_lock);
662 wLock.lock();
663 data->fileId++;
664 fi->fh = static_cast<uint64_t>(data->fileId);
665 wLock.unlock();
666 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
667 if (inoPtr == nullptr) {
668 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::OPEN,
669 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
670 fuse_reply_err(req, EINVAL);
671 return;
672 }
673 string path = CloudFileUtils::GetLocalFilePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
674 unsigned int flags = GetFileOpenFlags(fi->flags);
675 if (access(path.c_str(), F_OK) == 0) {
676 int32_t fd = open(path.c_str(), flags);
677 if (fd < 0) {
678 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::OPEN,
679 CloudFile::FaultType::FILE, errno, "open file failed path:" + GetAnonyString(path) +
680 " errno: " + std::to_string(errno)});
681 fuse_inval(data->se, inoPtr->parent, ino, inoPtr->fileName);
682 return (void) fuse_reply_err(req, errno);
683 }
684 struct stat statInfo {};
685 if (fstat(fd, &statInfo) != 0) {
686 LOGE("fstat path %{public}s failed, errno %{public}d", GetAnonyString(path).c_str(), errno);
687 close(fd);
688 return (void) fuse_reply_err(req, errno);
689 }
690 auto filePtr = InitFileAttr(data, fi);
691 filePtr->type = CLOUD_DISK_FILE_TYPE_LOCAL;
692 filePtr->fd = fd;
693 filePtr->isWriteOpen = (flags & O_RDWR) | (flags & O_WRONLY);
694 filePtr->mtime = static_cast<uint64_t>(CloudFileUtils::Timespec2Milliseconds(statInfo.st_mtim));
695 fuse_reply_open(req, fi);
696 } else {
697 path = CloudFileUtils::GetLocalDKCachePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
698 CloudOpen(req, inoPtr, fi, path, ino);
699 }
700 }
701
CreateLocalFile(const string & cloudId,const string & bundleName,int32_t userId,mode_t mode)702 static int32_t CreateLocalFile(const string &cloudId, const string &bundleName, int32_t userId, mode_t mode)
703 {
704 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
705 string bucketPath = CloudFileUtils::GetLocalBucketPath(cloudId, bundleName, userId);
706 string path = CloudFileUtils::GetLocalFilePath(cloudId, bundleName, userId);
707 if (access(bucketPath.c_str(), F_OK) != 0) {
708 if (mkdir(bucketPath.c_str(), STAT_MODE_DIR) != 0) {
709 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::MKNOD,
710 CloudFile::FaultType::FILE, errno, "mkdir bucketpath failed :" + GetAnonyString(bucketPath) +
711 " err: " + std::to_string(errno)});
712 return -errno;
713 }
714 }
715 int32_t fd = open(path.c_str(), (mode & O_NOFOLLOW) | O_CREAT | O_RDWR, STAT_MODE_REG);
716 if (fd < 0) {
717 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::MKNOD,
718 CloudFile::FaultType::FILE, errno, "create file failed :" + GetAnonyString(path) +
719 " err: " + std::to_string(errno)});
720 return -errno;
721 }
722 return fd;
723 }
724
RemoveLocalFile(const string & path)725 void RemoveLocalFile(const string &path)
726 {
727 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
728 int32_t err = remove(path.c_str());
729 if (err != 0) {
730 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::MKNOD,
731 CloudFile::FaultType::WARNING, errno, "remove file " + GetAnonyString(path) + " failed, "+
732 "error: " + std::to_string(errno)});
733 }
734 }
735
GenerateCloudId(int32_t userId,string & cloudId,const string & bundleName)736 int32_t GenerateCloudId(int32_t userId, string &cloudId, const string &bundleName)
737 {
738 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
739 auto dkDatabasePtr = GetDatabase(userId, bundleName);
740 if (dkDatabasePtr == nullptr) {
741 LOGE("Failed to get database");
742 return ENOSYS;
743 }
744
745 vector<std::string> ids;
746 auto ret = dkDatabasePtr->GenerateIds(1, ids);
747 if (ret != 0 || ids.size() == 0) {
748 return ENOSYS;
749 }
750 cloudId = ids[0];
751 return 0;
752 }
753
GetParentUpload(shared_ptr<CloudDiskInode> parentInode,struct CloudDiskFuseData * data,bool & parentNoUpload)754 static int32_t GetParentUpload(shared_ptr<CloudDiskInode> parentInode, struct CloudDiskFuseData *data,
755 bool &parentNoUpload)
756 {
757 auto grandparentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parentInode->parent));
758 if (grandparentInode == nullptr) {
759 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::MKNOD,
760 CloudFile::FaultType::INODE_FILE, EINVAL, "grandparentInode not found"});
761 return EINVAL;
762 }
763 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
764 grandparentInode->bundleName, grandparentInode->cloudId);
765 MetaBase metaBase(parentInode->fileName);
766 auto ret = metaFile->DoLookup(metaBase);
767 if (ret != 0) {
768 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{grandparentInode->bundleName,
769 CloudFile::FaultOperation::MKNOD, CloudFile::FaultType::DENTRY_FILE, ret, "file " +
770 GetAnonyString(parentInode->fileName) + " not found"});
771 return ret;
772 }
773 parentNoUpload = (metaBase.noUpload == NO_UPLOAD);
774 return 0;
775 }
776
DoCreatFile(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode,struct fuse_entry_param & e)777 int32_t DoCreatFile(fuse_req_t req, fuse_ino_t parent, const char *name,
778 mode_t mode, struct fuse_entry_param &e)
779 {
780 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
781 struct CloudDiskFuseData *data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
782 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
783 if (parentInode == nullptr) {
784 LOGE("parent inode not found");
785 return -EINVAL;
786 }
787 string cloudId;
788 int32_t err = GenerateCloudId(data->userId, cloudId, parentInode->bundleName);
789 if (err != 0) {
790 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::MKNOD,
791 CloudFile::FaultType::FILE, err, "Failed to generate cloud id"});
792 return -err;
793 }
794 int32_t fd = CreateLocalFile(cloudId, parentInode->bundleName, data->userId, mode);
795 if (fd < 0) {
796 LOGD("Create local file failed error:%{public}d", fd);
797 return fd;
798 }
799 string path = CloudFileUtils::GetLocalFilePath(cloudId, parentInode->bundleName, data->userId);
800 bool noNeedUpload = false;
801 if (parentInode->cloudId != ROOT_CLOUD_ID) {
802 err = GetParentUpload(parentInode, data, noNeedUpload);
803 if (err != 0) {
804 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::MKNOD,
805 CloudFile::FaultType::FILE, err, "Failed to get parent no upload"});
806 close(fd);
807 RemoveLocalFile(path);
808 return -err;
809 }
810 }
811 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
812 shared_ptr<CloudDiskRdbStore> rdbStore =
813 databaseManager.GetRdbStore(parentInode->bundleName, data->userId);
814 err = rdbStore->Create(cloudId, parentInode->cloudId, name, noNeedUpload);
815 if (err != 0) {
816 close(fd);
817 RemoveLocalFile(path);
818 return -EINVAL;
819 }
820 err = DoCloudLookup(req, parent, name, &e);
821 if (err != 0) {
822 close(fd);
823 RemoveLocalFile(path);
824 return -err;
825 }
826 return fd;
827 }
828
MkNod(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode,dev_t rdev)829 void FileOperationsCloud::MkNod(fuse_req_t req, fuse_ino_t parent, const char *name,
830 mode_t mode, dev_t rdev)
831 {
832 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
833 LOGE("wait move error");
834 return (void) fuse_reply_err(req, EBUSY);
835 }
836 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
837 struct fuse_entry_param e;
838 int32_t err = DoCreatFile(req, parent, name, mode, e);
839 if (err < 0) {
840 fuse_reply_err(req, -err);
841 return;
842 }
843 close(err);
844 fuse_reply_entry(req, &e);
845 }
846
Create(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode,struct fuse_file_info * fi)847 void FileOperationsCloud::Create(fuse_req_t req, fuse_ino_t parent, const char *name,
848 mode_t mode, struct fuse_file_info *fi)
849 {
850 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
851 LOGE("wait move error");
852 return (void) fuse_reply_err(req, EBUSY);
853 }
854 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
855 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
856 struct fuse_entry_param e;
857 int32_t err = DoCreatFile(req, parent, name, mode, e);
858 if (err < 0) {
859 fuse_reply_err(req, -err);
860 return;
861 }
862 auto filePtr = InitFileAttr(data, fi);
863 std::unique_lock<std::shared_mutex> wLock(data->fileIdLock, std::defer_lock);
864 wLock.lock();
865 data->fileId++;
866 fi->fh = static_cast<uint64_t>(data->fileId);
867 wLock.unlock();
868 filePtr->fd = err;
869 filePtr->type = CLOUD_DISK_FILE_TYPE_LOCAL;
870 filePtr->fileDirty = CLOUD_DISK_FILE_CREATE;
871 fuse_reply_create(req, &e, fi);
872 }
873
FindNextPos(const vector<CloudDiskFileInfo> & childInfos,off_t off)874 static size_t FindNextPos(const vector<CloudDiskFileInfo> &childInfos, off_t off)
875 {
876 for (size_t i = 0; i < childInfos.size(); i++) {
877 /* Find the first valid offset beyond @off */
878 if (childInfos[i].nextOff > off) {
879 return i + 1;
880 }
881 }
882 /* If @off is beyond all valid offset, then return the index after the last info */
883 if (!childInfos.empty() && childInfos.back().nextOff < off) {
884 return childInfos.size();
885 }
886 return 0;
887 }
888
FindNextPos(const vector<MetaBase> & childInfos,off_t off)889 static size_t FindNextPos(const vector<MetaBase> &childInfos, off_t off)
890 {
891 for (size_t i = 0; i < childInfos.size(); i++) {
892 /* Find the first valid offset beyond @off */
893 if (childInfos[i].nextOff > off) {
894 return i + 1;
895 }
896 }
897 /* If @off is beyond all valid offset, then return the index after the last info */
898 if (!childInfos.empty() && childInfos.back().nextOff < off) {
899 return childInfos.size();
900 }
901 return 0;
902 }
903
GetChildInfos(fuse_req_t req,fuse_ino_t ino,vector<CloudDiskFileInfo> & childInfos)904 static int32_t GetChildInfos(fuse_req_t req, fuse_ino_t ino, vector<CloudDiskFileInfo> &childInfos)
905 {
906 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
907 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
908 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
909 if (inoPtr == nullptr) {
910 LOGE("inode not found");
911 return EINVAL;
912 }
913 string parentCloudId = inoPtr->cloudId;
914
915 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
916 shared_ptr<CloudDiskRdbStore> rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
917 int32_t err = rdbStore->ReadDir(parentCloudId, childInfos);
918 if (err != 0) {
919 LOGE("Readdir failed cloudId:%{public}s err:%{public}d", parentCloudId.c_str(), err);
920 return err;
921 }
922 return 0;
923 }
924
925 template<typename T>
CloudSeekDir(fuse_req_t req,fuse_ino_t ino,off_t off,const std::vector<T> & childInfos)926 static size_t CloudSeekDir(fuse_req_t req, fuse_ino_t ino, off_t off,
927 const std::vector<T> &childInfos)
928 {
929 if (off == 0 || childInfos.empty()) {
930 return 0;
931 }
932
933 size_t i = 0;
934 for (; i < childInfos.size(); i++) {
935 if (childInfos[i].nextOff == off) {
936 /* Start position should be the index of next entry */
937 return i + 1;
938 }
939 }
940 if (i == childInfos.size()) {
941 /* The directory may changed recently, find the next valid index for this offset */
942 return FindNextPos(childInfos, off);
943 }
944
945 return 0;
946 }
947
948 template<typename T>
AddDirEntryToBuf(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,const std::vector<T> & childInfos)949 static void AddDirEntryToBuf(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
950 const std::vector<T> &childInfos)
951 {
952 size_t startPos = CloudSeekDir<T>(req, ino, off, childInfos);
953 string buf;
954 buf.resize(size);
955 if (childInfos.empty() || startPos == childInfos.size()) {
956 LOGW("empty buffer replied");
957 return (void)fuse_reply_buf(req, buf.c_str(), 0);
958 }
959
960 size_t nextOff = 0;
961 size_t remain = size;
962 static const struct stat statInfoDir = { .st_mode = S_IFDIR | STAT_MODE_DIR };
963 static const struct stat statInfoReg = { .st_mode = S_IFREG | STAT_MODE_REG };
964 for (size_t i = startPos; i < childInfos.size(); i++) {
965 size_t alignSize = CloudDiskRdbUtils::FuseDentryAlignSize(childInfos[i].name.c_str());
966 if (alignSize > remain) {
967 break;
968 }
969 alignSize = fuse_add_direntry(req, &buf[nextOff], alignSize, childInfos[i].name.c_str(),
970 childInfos[i].mode != S_IFREG ? &statInfoDir : &statInfoReg,
971 off + static_cast<off_t>(nextOff) + static_cast<off_t>(alignSize));
972 nextOff += alignSize;
973 remain -= alignSize;
974 }
975 (void)fuse_reply_buf(req, buf.c_str(), size - remain);
976 }
977
ReadDirForRecycle(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)978 static void ReadDirForRecycle(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
979 struct fuse_file_info *fi)
980 {
981 int32_t err = -1;
982 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
983 auto inode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
984 if (inode == nullptr) {
985 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READDIR,
986 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
987 fuse_reply_err(req, EINVAL);
988 return;
989 }
990 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
991 inode->bundleName, RECYCLE_NAME);
992 std::vector<MetaBase> childInfos;
993 err = metaFile->LoadChildren(childInfos);
994 if (err != 0) {
995 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inode->bundleName, CloudFile::FaultOperation::READDIR,
996 CloudFile::FaultType::DENTRY_FILE, err, "load children failed, err = " + std::to_string(err)});
997 fuse_reply_err(req, EINVAL);
998 return;
999 }
1000 size_t nextOff = 0;
1001 for (size_t i = 0; i < childInfos.size(); ++i) {
1002 size_t alignSize = CloudDiskRdbUtils::FuseDentryAlignSize(childInfos[i].name.c_str());
1003 nextOff += alignSize;
1004 childInfos[i].nextOff = static_cast<off_t>(nextOff);
1005 }
1006 AddDirEntryToBuf(req, ino, size, off, childInfos);
1007 }
1008
ReadDir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)1009 void FileOperationsCloud::ReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
1010 struct fuse_file_info *fi)
1011 {
1012 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1013 LOGE("wait move error");
1014 return (void) fuse_reply_err(req, EBUSY);
1015 }
1016 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1017 if (ino == RECYCLE_LOCAL_ID) {
1018 ReadDirForRecycle(req, ino, size, off, fi);
1019 return;
1020 }
1021
1022 vector<CloudDiskFileInfo> childInfos;
1023 int32_t err = GetChildInfos(req, ino, childInfos);
1024 if (err != 0) {
1025 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READDIR,
1026 CloudFile::FaultType::QUERY_DATABASE, err, "failed to get child infos, err = " + std::to_string(err)});
1027 return (void)fuse_reply_err(req, EINVAL);
1028 }
1029 AddDirEntryToBuf(req, ino, size, off, childInfos);
1030 }
1031
CheckXattr(const char * name)1032 int32_t CheckXattr(const char *name)
1033 {
1034 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1035 LOGD("start CheckXattr name is:%{public}s", name);
1036 if (CloudFileUtils::CheckIsHmdfsPermission(name)) {
1037 return HMDFS_PERMISSION;
1038 } else if (CloudFileUtils::CheckIsCloudLocation(name)) {
1039 return CLOUD_LOCATION;
1040 } else if (CloudFileUtils::CheckIsCloudRecycle(name)) {
1041 return CLOUD_RECYCLE;
1042 } else if (CloudFileUtils::CheckIsFavorite(name)) {
1043 return IS_FAVORITE;
1044 } else if (CloudFileUtils::CheckIsHasLCD(name) || CloudFileUtils::CheckIsHasTHM(name)) {
1045 return HAS_THM;
1046 } else {
1047 LOGD("no definition Xattr name:%{public}s", name);
1048 return ERROR_CODE;
1049 }
1050 }
1051
HandleCloudLocation(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)1052 void HandleCloudLocation(fuse_req_t req, fuse_ino_t ino, const char *name,
1053 const char *value)
1054 {
1055 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1056 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1057 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1058 if (inoPtr == nullptr) {
1059 fuse_reply_err(req, EINVAL);
1060 LOGE("inode not found");
1061 return;
1062 }
1063 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(inoPtr->parent));
1064 if (parentInode == nullptr) {
1065 LOGE("parent inode not found");
1066 return (void) fuse_reply_err(req, EINVAL);
1067 }
1068 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1069 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1070 int32_t err = rdbStore->SetXAttr(inoPtr->cloudId, CLOUD_FILE_LOCATION, value, inoPtr->fileName,
1071 parentInode->cloudId);
1072 if (err != 0) {
1073 LOGE("set cloud id fail %{public}d", err);
1074 fuse_reply_err(req, EINVAL);
1075 return;
1076 }
1077 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1078 NotifyOpsType::DAEMON_SETXATTR, inoPtr});
1079 fuse_reply_err(req, 0);
1080 }
1081
HandleCloudRecycle(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)1082 void HandleCloudRecycle(fuse_req_t req, fuse_ino_t ino, const char *name,
1083 const char *value)
1084 {
1085 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1086 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1087 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1088 if (inoPtr == nullptr) {
1089 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::SETEXTATTR,
1090 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
1091 fuse_reply_err(req, EINVAL);
1092 return;
1093 }
1094 string parentCloudId;
1095 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1096 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(inoPtr->parent));
1097 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1098 if (parentInode == nullptr) {
1099 int32_t ret = rdbStore->GetParentCloudId(inoPtr->cloudId, parentCloudId);
1100 if (ret != 0) {
1101 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::SETEXTATTR,
1102 CloudFile::FaultType::DATABASE, ret, "fail to get parentCloudId"});
1103 fuse_reply_err(req, EINVAL);
1104 return;
1105 }
1106 } else {
1107 parentCloudId = parentInode->cloudId;
1108 }
1109 int32_t ret = MetaFileMgr::GetInstance().CreateRecycleDentry(data->userId, inoPtr->bundleName);
1110 if (ret != 0) {
1111 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName,
1112 CloudFile::FaultOperation::SETEXTATTR, CloudFile::FaultType::DENTRY_FILE, ret,
1113 "create recycle dentry failed"});
1114 fuse_reply_err(req, ret);
1115 return;
1116 }
1117 ret = rdbStore->SetXAttr(inoPtr->cloudId, CLOUD_CLOUD_RECYCLE_XATTR, value,
1118 inoPtr->fileName, parentCloudId);
1119 if (ret != 0) {
1120 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName,
1121 CloudFile::FaultOperation::SETEXTATTR, CloudFile::FaultType::MODIFY_DATABASE, ret,
1122 "set cloud recycle xattr fail, ret = " + std::to_string(ret)});
1123 fuse_reply_err(req, EINVAL);
1124 return;
1125 }
1126 int32_t val = std::stoi(value);
1127 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1128 val == 0 ? NotifyOpsType::DAEMON_RESTORE : NotifyOpsType::DAEMON_RECYCLE, inoPtr});
1129 fuse_reply_err(req, 0);
1130 }
1131
HandleFavorite(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)1132 void HandleFavorite(fuse_req_t req, fuse_ino_t ino, const char *name,
1133 const char *value)
1134 {
1135 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1136 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1137 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1138 if (inoPtr == nullptr) {
1139 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::SETEXTATTR,
1140 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
1141 fuse_reply_err(req, EINVAL);
1142 return;
1143 }
1144 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1145 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1146 int32_t err = rdbStore->SetXAttr(inoPtr->cloudId, IS_FAVORITE_XATTR, value);
1147 if (err != 0) {
1148 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName, CloudFile::FaultOperation::SETEXTATTR,
1149 CloudFile::FaultType::MODIFY_DATABASE, err, "set cloud is favorite xattr fail, err = " +
1150 std::to_string(err)});
1151 fuse_reply_err(req, EINVAL);
1152 return;
1153 }
1154 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1155 NotifyOpsType::DAEMON_SETXATTR, inoPtr});
1156 fuse_reply_err(req, 0);
1157 }
1158
HandleHasTHM(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)1159 void HandleHasTHM(fuse_req_t req, fuse_ino_t ino, const char *name,
1160 const char *value)
1161 {
1162 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1163 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1164 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1165 if (inoPtr == nullptr) {
1166 fuse_reply_err(req, EINVAL);
1167 std::string errMsg = "inode not found";
1168 CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{"", CloudFile::FaultOperation::SETATTR,
1169 CloudFile::FaultType::DENTRY_FILE, EINVAL, errMsg});
1170 return;
1171 }
1172 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1173 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1174 int32_t err = rdbStore->SetXAttr(inoPtr->cloudId, name, value);
1175 if (err != 0) {
1176 std::string errMsg = "set has thm fail " + to_string(err);
1177 CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{inoPtr->bundleName, CloudFile::FaultOperation::SETATTR,
1178 CloudFile::FaultType::DENTRY_FILE, EINVAL, errMsg});
1179 fuse_reply_err(req, EINVAL);
1180 return;
1181 }
1182 fuse_reply_err(req, 0);
1183 }
1184
HandleExtAttribute(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)1185 void HandleExtAttribute(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value)
1186 {
1187 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1188 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1189 if (inoPtr == nullptr) {
1190 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::SETEXTATTR,
1191 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
1192 fuse_reply_err(req, EINVAL);
1193 return;
1194 }
1195 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1196 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1197 int32_t err = rdbStore->SetXAttr(inoPtr->cloudId, CLOUD_EXT_ATTR, value, name);
1198 if (err != 0) {
1199 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName, CloudFile::FaultOperation::SETEXTATTR,
1200 CloudFile::FaultType::MODIFY_DATABASE, err, "set cloud ext attr fail, err = " + std::to_string(err)});
1201 fuse_reply_err(req, EINVAL);
1202 return;
1203 }
1204 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1205 NotifyOpsType::DAEMON_SETXATTR, inoPtr});
1206 fuse_reply_err(req, 0);
1207 }
1208
SetXattr(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value,size_t size,int flags)1209 void FileOperationsCloud::SetXattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1210 const char *value, size_t size, int flags)
1211 {
1212 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1213 LOGE("wait move error");
1214 return (void) fuse_reply_err(req, EBUSY);
1215 }
1216 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1217 LOGD("Setxattr begin name:%{public}s", name);
1218 int32_t checknum = CheckXattr(name);
1219 switch (checknum) {
1220 case HMDFS_PERMISSION:
1221 fuse_reply_err(req, 0);
1222 break;
1223 case CLOUD_LOCATION:
1224 HandleCloudLocation(req, ino, name, value);
1225 break;
1226 case CLOUD_RECYCLE:
1227 HandleCloudRecycle(req, ino, name, value);
1228 break;
1229 case IS_FAVORITE:
1230 HandleFavorite(req, ino, name, value);
1231 break;
1232 case HAS_THM:
1233 HandleHasTHM(req, ino, name, value);
1234 break;
1235 default:
1236 HandleExtAttribute(req, ino, name, value);
1237 break;
1238 }
1239 }
1240
GetIsFavorite(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr)1241 string GetIsFavorite(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr)
1242 {
1243 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1244 string favorite;
1245 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1246 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1247 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1248 int res = rdbStore->GetXAttr(inoPtr->cloudId, IS_FAVORITE_XATTR, favorite);
1249 if (res != 0) {
1250 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETEXTATTR,
1251 CloudFile::FaultType::QUERY_DATABASE, res, "local file get isFavorite fail"});
1252 return "null";
1253 }
1254 return favorite;
1255 }
1256
GetFileStatus(fuse_req_t req,struct CloudDiskInode * inoPtr)1257 static string GetFileStatus(fuse_req_t req, struct CloudDiskInode *inoPtr)
1258 {
1259 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1260 string fileStatus;
1261 if (inoPtr == nullptr) {
1262 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETEXTATTR,
1263 CloudFile::FaultType::INODE_FILE, EINVAL, "inoPtr is null"});
1264 return "null";
1265 }
1266 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1267 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1268 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1269 int res = rdbStore->GetXAttr(inoPtr->cloudId, IS_FILE_STATUS_XATTR, fileStatus);
1270 if (res != 0) {
1271 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETEXTATTR,
1272 CloudFile::FaultType::QUERY_DATABASE, res, "local file get file_status fail"});
1273 return "null";
1274 }
1275 return fileStatus;
1276 }
1277
GetLocation(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr)1278 string GetLocation(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr)
1279 {
1280 string location;
1281 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1282 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1283 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1284 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(inoPtr->parent));
1285 if (parentInode == nullptr) {
1286 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETEXTATTR,
1287 CloudFile::FaultType::INODE_FILE, EINVAL, "parent inode not found"});
1288 return "null";
1289 }
1290 CacheNode newNode = {.parentCloudId = parentInode->cloudId, .fileName = inoPtr->fileName};
1291 int res = rdbStore->GetXAttr(inoPtr->cloudId, CLOUD_FILE_LOCATION, location, newNode);
1292 if (res != 0) {
1293 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETEXTATTR,
1294 CloudFile::FaultType::QUERY_DATABASE, res, "local file get location fail"});
1295 return "null";
1296 }
1297 return location;
1298 }
1299
GetTimeRecycled(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr)1300 string GetTimeRecycled(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr)
1301 {
1302 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1303 string timeRecycled;
1304 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1305 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1306 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1307 int res = rdbStore->GetXAttr(inoPtr->cloudId, CLOUD_TIME_RECYCLED, timeRecycled);
1308 if (res != 0) {
1309 LOGE("local file get time recycled fail");
1310 return "null";
1311 }
1312 return timeRecycled;
1313 }
1314
GetRecyclePath(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr)1315 string GetRecyclePath(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr)
1316 {
1317 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1318 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1319 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1320 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1321 int64_t rowId;
1322 int res = rdbStore->GetRowId(inoPtr->cloudId, rowId);
1323 if (res != 0) {
1324 LOGE("local file get recycle path fail");
1325 return "null";
1326 }
1327 string recyclePath = LOCAL_PATH_DATA_STORAGE + RECYCLE_NAME + "/" +
1328 inoPtr->fileName + "_" + to_string(rowId);
1329 return recyclePath;
1330 }
1331
GetExtAttr(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr,const char * extAttrKey)1332 string GetExtAttr(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr, const char *extAttrKey)
1333 {
1334 string extAttr;
1335 if (inoPtr == nullptr) {
1336 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETEXTATTR,
1337 CloudFile::FaultType::INODE_FILE, EINVAL, "get ext attr inoPtr is null"});
1338 return "null";
1339 }
1340
1341 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1342 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1343 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1344 CacheNode newNode = {};
1345 int res = rdbStore->GetXAttr(inoPtr->cloudId, CLOUD_EXT_ATTR, extAttr, newNode, extAttrKey);
1346 if (res != 0) {
1347 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETEXTATTR,
1348 CloudFile::FaultType::FILE, res, "get ext attr is null"});
1349 return "null";
1350 }
1351 return extAttr;
1352 }
1353
GetXattr(fuse_req_t req,fuse_ino_t ino,const char * name,size_t size)1354 void FileOperationsCloud::GetXattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1355 size_t size)
1356 {
1357 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1358 LOGE("wait move error");
1359 return (void) fuse_reply_err(req, EBUSY);
1360 }
1361 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1362 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1363 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1364 if (inoPtr == nullptr) {
1365 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETEXTATTR,
1366 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
1367 fuse_reply_err(req, EINVAL);
1368 return;
1369 }
1370 string buf;
1371 if (CloudFileUtils::CheckIsHmdfsPermission(name)) {
1372 buf = to_string(inoPtr->layer + CLOUD_FILE_LAYER);
1373 } else if (CloudFileUtils::CheckIsCloud(name)) {
1374 buf = inoPtr->cloudId;
1375 } else if (CloudFileUtils::CheckIsFavorite(name)) {
1376 buf = GetIsFavorite(req, inoPtr);
1377 } else if (CloudFileUtils::CheckFileStatus(name)) {
1378 buf = GetFileStatus(req, inoPtr.get());
1379 } else if (CloudFileUtils::CheckIsCloudLocation(name)) {
1380 buf = GetLocation(req, inoPtr);
1381 } else if (CloudFileUtils::CheckIsTimeRecycled(name)) {
1382 buf = GetTimeRecycled(req, inoPtr);
1383 } else if (CloudFileUtils::CheckIsRecyclePath(name)) {
1384 buf = GetRecyclePath(req, inoPtr);
1385 } else {
1386 buf = GetExtAttr(req, inoPtr, name);
1387 }
1388 if (buf == "null") {
1389 fuse_reply_err(req, ENODATA);
1390 return;
1391 }
1392 if (size == 0) {
1393 fuse_reply_xattr(req, buf.size());
1394 return;
1395 }
1396 if (buf.size() > size) {
1397 fuse_reply_err(req, ERANGE);
1398 return;
1399 }
1400 if (buf.size() > 0) {
1401 fuse_reply_buf(req, buf.c_str(), buf.size());
1402 } else {
1403 fuse_reply_err(req, 0);
1404 }
1405 }
1406
MkDir(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode)1407 void FileOperationsCloud::MkDir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
1408 {
1409 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1410 LOGE("wait move error");
1411 return (void) fuse_reply_err(req, EBUSY);
1412 }
1413 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1414 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1415 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
1416 if (parentInode == nullptr) {
1417 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::MKDIR,
1418 CloudFile::FaultType::INNER_ERROR, EINVAL, "parent inode not found"});
1419 return (void) fuse_reply_err(req, EINVAL);
1420 }
1421 string fileName = name;
1422 bool noNeedUpload;
1423 if ((fileName == ".cloudthumbnails" || fileName == ".conflict") && parentInode->cloudId == ROOT_CLOUD_ID) {
1424 noNeedUpload = true;
1425 } else if (parentInode->cloudId != ROOT_CLOUD_ID) {
1426 int32_t err = GetParentUpload(parentInode, data, noNeedUpload);
1427 if (err != 0) {
1428 LOGE("Failed to get parent no upload");
1429 return (void) fuse_reply_err(req, err);
1430 }
1431 }
1432 string cloudId;
1433 int32_t err = GenerateCloudId(data->userId, cloudId, parentInode->bundleName);
1434 if (err != 0) {
1435 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1436 CloudFile::FaultOperation::MKDIR, CloudFile::FaultType::FILE, err, "Failed to generate cloud id"});
1437 return (void) fuse_reply_err(req, err);
1438 }
1439
1440 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1441 shared_ptr<CloudDiskRdbStore> rdbStore = databaseManager.GetRdbStore(parentInode->bundleName, data->userId);
1442 err = rdbStore->MkDir(cloudId, parentInode->cloudId, name, noNeedUpload);
1443 if (err != 0) {
1444 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::MKDIR,
1445 CloudFile::FaultType::DATABASE, err, "Failed to mkdir to DB err:" + std::to_string(err)});
1446 return (void) fuse_reply_err(req, EINVAL);
1447 }
1448
1449 struct fuse_entry_param e;
1450 err = DoCloudLookup(req, parent, name, &e);
1451 if (err != 0) {
1452 LOGE("Failed to find dir %{private}s", GetAnonyString(name).c_str());
1453 fuse_reply_err(req, err);
1454 } else {
1455 fuse_reply_entry(req, &e);
1456 }
1457 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1458 NotifyOpsType::DAEMON_MKDIR, parentInode, parent, name});
1459 }
1460
RDBUnlinkAsync(shared_ptr<CloudDiskRdbStore> rdbStore,const string & cloudId,int32_t noUpload)1461 void RDBUnlinkAsync(shared_ptr<CloudDiskRdbStore> rdbStore, const string& cloudId, int32_t noUpload)
1462 {
1463 function<void()> rdbUnlink = [rdbStore, cloudId, noUpload] {
1464 if (rdbStore->Unlink(cloudId, noUpload) != 0) {
1465 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"",
1466 CloudFile::FaultOperation::UNLINK, CloudFile::FaultType::DATABASE, EINVAL,
1467 "Failed to unlink DB cloudId: " + cloudId});
1468 }
1469 };
1470 ffrt::thread(rdbUnlink).detach();
1471 }
1472
DoCloudUnlink(fuse_req_t req,fuse_ino_t parent,const char * name)1473 int32_t DoCloudUnlink(fuse_req_t req, fuse_ino_t parent, const char *name)
1474 {
1475 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1476 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1477 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
1478 if (parentInode == nullptr) {
1479 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::UNLINK,
1480 CloudFile::FaultType::INODE_FILE, EINVAL, "parent inode not found"});
1481 return EINVAL;
1482 }
1483 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1484 shared_ptr<CloudDiskRdbStore> rdbStore = databaseManager.GetRdbStore(parentInode->bundleName, data->userId);
1485 MetaBase metaBase(name);
1486 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
1487 parentInode->bundleName, parentInode->cloudId);
1488 if (int32_t ret = metaFile->DoLookup(metaBase); ret != 0) {
1489 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1490 CloudFile::FaultOperation::UNLINK, CloudFile::FaultType::DENTRY_FILE, ret,
1491 "lookup denty failed, name: " + GetAnonyString(name)});
1492 return ret;
1493 }
1494 string cloudId = metaBase.cloudId;
1495 int32_t isDirectory = S_ISDIR(metaBase.mode);
1496 int32_t position = metaBase.position;
1497 int32_t noUpload = metaBase.noUpload;
1498 if (int32_t ret = metaFile->DoRemove(metaBase); ret != 0) {
1499 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1500 CloudFile::FaultOperation::UNLINK, CloudFile::FaultType::DENTRY_FILE, ret, "remove dentry failed, ret = " +
1501 std::to_string(ret)});
1502 return ret;
1503 }
1504 LOGD("doUnlink, dentry file has been deleted");
1505 if (isDirectory == FILE && position != CLOUD) {
1506 string localPath = CloudFileUtils::GetLocalFilePath(cloudId, parentInode->bundleName, data->userId);
1507 LOGI("unlink %{public}s", GetAnonyString(localPath).c_str());
1508 int32_t ret = unlink(localPath.c_str());
1509 if (ret != 0 && errno == ENOENT) {
1510 std::string errMsg = "doCloudUnlink, unlink local file ret ENOENT.";
1511 CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{parentInode->bundleName, CloudFile::FaultOperation::UNLINK,
1512 CloudFile::FaultType::WARNING, errno, errMsg});
1513 } else if (ret != 0) {
1514 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1515 CloudFile::FaultOperation::UNLINK, CloudFile::FaultType::FILE, errno,
1516 "Failed to unlink cloudId:" + cloudId + ", errno: " + std::to_string(errno)});
1517 (void)metaFile->DoCreate(metaBase);
1518 return errno;
1519 }
1520 }
1521 RDBUnlinkAsync(rdbStore, cloudId, noUpload);
1522 return 0;
1523 }
1524
LoadMetaFileChildren(const CloudDiskFuseData * data,const MetaBase & metaBase,shared_ptr<CloudDiskInode> parentInode,const fuse_req_t & req)1525 std::shared_ptr<CloudDiskMetaFile> LoadMetaFileChildren(const CloudDiskFuseData* data, const MetaBase& metaBase,
1526 shared_ptr<CloudDiskInode> parentInode, const fuse_req_t& req)
1527 {
1528 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
1529 parentInode->bundleName, metaBase.cloudId);
1530 std::vector<MetaBase> bases;
1531 if (int err = metaFile->LoadChildren(bases); err != 0) {
1532 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1533 CloudFile::FaultOperation::RMDIR, CloudFile::FaultType::DENTRY_FILE, err, "load children failed, err = " +
1534 std::to_string(err)});
1535 fuse_reply_err(req, EINVAL);
1536 return nullptr;
1537 }
1538 if (!bases.empty()) {
1539 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1540 CloudFile::FaultOperation::RMDIR, CloudFile::FaultType::DENTRY_FILE, ENOTEMPTY, "Directory not empty"});
1541 fuse_reply_err(req, ENOTEMPTY);
1542 return nullptr;
1543 }
1544 return metaFile;
1545 }
1546
RmDir(fuse_req_t req,fuse_ino_t parent,const char * name)1547 void FileOperationsCloud::RmDir(fuse_req_t req, fuse_ino_t parent, const char *name)
1548 {
1549 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1550 LOGE("wait move error");
1551 return (void) fuse_reply_err(req, EBUSY);
1552 }
1553 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1554
1555 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1556 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
1557 if (parentInode == nullptr) {
1558 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::RMDIR,
1559 CloudFile::FaultType::INODE_FILE, EINVAL, "parent inode not found"});
1560 return (void) fuse_reply_err(req, EINVAL);
1561 }
1562 auto parentMetaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
1563 parentInode->bundleName, parentInode->cloudId);
1564 MetaBase metaBase(name);
1565 int32_t err = parentMetaFile->DoLookup(metaBase);
1566 if (err != 0) {
1567 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1568 CloudFile::FaultOperation::RMDIR, CloudFile::FaultType::DENTRY_FILE, err, "lookup dir failed, err = " +
1569 std::to_string(err)});
1570 return (void) fuse_reply_err(req, EINVAL);
1571 }
1572
1573 std::shared_ptr<CloudDiskMetaFile> metaFile = LoadMetaFileChildren(data, metaBase, parentInode, req);
1574 if (metaFile == nullptr) {
1575 return;
1576 }
1577
1578 err = DoCloudUnlink(req, parent, name);
1579 if (err != 0) {
1580 fuse_reply_err(req, err);
1581 return;
1582 }
1583 MetaFileMgr::GetInstance().Clear(static_cast<uint32_t>(data->userId), parentInode->bundleName, metaBase.cloudId);
1584 if (unlink(metaFile->GetDentryFilePath().c_str()) != 0) {
1585 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1586 CloudFile::FaultOperation::RMDIR, CloudFile::FaultType::WARNING, errno, "fail to delete dentry: " +
1587 std::to_string(errno)});
1588 }
1589 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1590 NotifyOpsType::DAEMON_RMDIR, nullptr, parent, name});
1591 return (void) fuse_reply_err(req, 0);
1592 }
1593
Unlink(fuse_req_t req,fuse_ino_t parent,const char * name)1594 void FileOperationsCloud::Unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
1595 {
1596 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1597 LOGE("wait move error");
1598 return (void) fuse_reply_err(req, EBUSY);
1599 }
1600 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1601 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1602 int32_t err = DoCloudUnlink(req, parent, name);
1603 if (err != 0) {
1604 fuse_reply_err(req, err);
1605 return;
1606 }
1607 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1608 NotifyOpsType::DAEMON_UNLINK, nullptr, parent, name});
1609 return (void) fuse_reply_err(req, 0);
1610 }
1611
Rename(fuse_req_t req,fuse_ino_t parent,const char * name,fuse_ino_t newParent,const char * newName,unsigned int flags)1612 void FileOperationsCloud::Rename(fuse_req_t req, fuse_ino_t parent, const char *name,
1613 fuse_ino_t newParent, const char *newName, unsigned int flags)
1614 {
1615 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1616 LOGE("wait move error");
1617 return (void) fuse_reply_err(req, EBUSY);
1618 }
1619 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1620 if (flags) {
1621 LOGE("Fuse failed to support flag");
1622 return (void) fuse_reply_err(req, EINVAL);
1623 }
1624 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1625 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
1626 auto newParentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(newParent));
1627 if (!parentInode || !newParentInode) {
1628 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::RENAME,
1629 CloudFile::FaultType::INODE_FILE, EINVAL, "rename old or new parent not found"});
1630 return (void) fuse_reply_err(req, EINVAL);
1631 }
1632
1633 bool noNeedUpload = false;
1634 if (newParentInode->cloudId != ROOT_CLOUD_ID) {
1635 int32_t err = GetParentUpload(newParentInode, data, noNeedUpload);
1636 if (err != 0) {
1637 LOGE("Failed to get parent no upload");
1638 return (void) fuse_reply_err(req, err);
1639 }
1640 }
1641
1642 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1643 shared_ptr<CloudDiskRdbStore> rdbStore = databaseManager.GetRdbStore(parentInode->bundleName, data->userId);
1644 int32_t err = rdbStore->Rename(parentInode->cloudId, name, newParentInode->cloudId, newName, noNeedUpload);
1645 if (err != 0) {
1646 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1647 CloudFile::FaultOperation::RENAME, CloudFile::FaultType::DATABASE, err,
1648 "Failed to Rename DB name: " + GetAnonyString(name) + "err:" + std::to_string(err)});
1649 return (void) fuse_reply_err(req, EINVAL);
1650 }
1651 bool isDir = false;
1652 string key = std::to_string(parent) + name;
1653 int64_t localId = FileOperationsHelper::FindLocalId(data, key);
1654 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, localId);
1655 if (inoPtr != nullptr) {
1656 inoPtr->fileName = newName;
1657 inoPtr->parent = newParent;
1658 isDir = S_ISDIR(inoPtr->stat.st_mode);
1659 }
1660 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1661 NotifyOpsType::DAEMON_RENAME, nullptr, parent, name, newParent, newName}, {FileStatus::UNKNOW, isDir});
1662 return (void) fuse_reply_err(req, 0);
1663 }
1664
DoCloudRead(fuse_req_t req,shared_ptr<CloudDiskFile> filePtr,off_t offset,size_t size,shared_ptr<char> buf)1665 static void DoCloudRead(fuse_req_t req, shared_ptr<CloudDiskFile> filePtr,
1666 off_t offset, size_t size, shared_ptr<char> buf)
1667 {
1668 auto readSize = make_shared<int64_t>();
1669 auto error = make_shared<CloudError>();
1670 auto readFinish = make_shared<bool>(false);
1671 auto cond = make_shared<ffrt::condition_variable>();
1672
1673 ffrt::submit([filePtr, error, readFinish, cond, offset, size, buf, readSize] {
1674 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1675 auto session = filePtr->readSession;
1676 if (!session) {
1677 LOGE("readSession is nullptr");
1678 {
1679 unique_lock lck(filePtr->readLock);
1680 *readFinish = true;
1681 }
1682 *error = CloudError::CK_LOCAL_ERROR;
1683 cond->notify_one();
1684 return;
1685 }
1686 *readSize = session->PRead(offset, size, buf.get(), *error);
1687 {
1688 unique_lock lck(filePtr->readLock);
1689 *readFinish = true;
1690 }
1691 cond->notify_one();
1692 LOGI("download done");
1693 return;
1694 });
1695
1696 unique_lock lck(filePtr->readLock);
1697 auto waitStatus = cond->wait_for(lck, READ_TIMEOUT_S, [readFinish] {
1698 return *readFinish;
1699 });
1700 if (!waitStatus) {
1701 LOGE("PRead timeout");
1702 fuse_reply_err(req, ENETUNREACH);
1703 return;
1704 }
1705 auto ret = HandleCloudError(req, *error);
1706 if (ret == 0) {
1707 filePtr->type = CLOUD_DISK_FILE_TYPE_CLOUD;
1708 fuse_reply_buf(req, buf.get(), *readSize);
1709 } else {
1710 LOGE("read fail");
1711 fuse_reply_err(req, ret);
1712 }
1713 return;
1714 }
1715
Read(fuse_req_t req,fuse_ino_t ino,size_t size,off_t offset,struct fuse_file_info * fi)1716 void FileOperationsCloud::Read(fuse_req_t req, fuse_ino_t ino, size_t size,
1717 off_t offset, struct fuse_file_info *fi)
1718 {
1719 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1720 if (size > MAX_READ_SIZE) {
1721 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READ,
1722 CloudFile::FaultType::WARNING, EINVAL, "Read size is larger than the kernel pre-read window"});
1723 fuse_reply_err(req, EINVAL);
1724 return;
1725 }
1726 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1727 auto filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
1728 if (filePtr == nullptr) {
1729 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READ,
1730 CloudFile::FaultType::FILE, EINVAL, "file not found"});
1731 fuse_reply_err(req, EINVAL);
1732 return;
1733 }
1734 if (filePtr->type == CLOUD_DISK_FILE_TYPE_LOCAL) {
1735 struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
1736
1737 buf.buf[0].flags = static_cast<fuse_buf_flags> (FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK);
1738 buf.buf[0].fd = filePtr->fd;
1739 buf.buf[0].pos = offset;
1740
1741 fuse_reply_data(req, &buf, static_cast<fuse_buf_copy_flags> (0));
1742 return;
1743 }
1744
1745 shared_ptr<char> buf = nullptr;
1746
1747 buf.reset(new char[size], [](char* ptr) {
1748 delete[] ptr;
1749 });
1750
1751 if (!buf) {
1752 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READ,
1753 CloudFile::FaultType::FILE, ENOMEM, "buffer is null"});
1754 fuse_reply_err(req, ENOMEM);
1755 return;
1756 }
1757 DoCloudRead(req, filePtr, offset, size, buf);
1758 }
1759
UpdateCloudDiskInode(shared_ptr<CloudDiskRdbStore> rdbStore,shared_ptr<CloudDiskInode> inoPtr)1760 static void UpdateCloudDiskInode(shared_ptr<CloudDiskRdbStore> rdbStore, shared_ptr<CloudDiskInode> inoPtr)
1761 {
1762 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1763 CloudDiskFileInfo childInfo;
1764 int32_t err = rdbStore->GetAttr(inoPtr->cloudId, childInfo);
1765 if (err != 0) {
1766 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETATTR,
1767 CloudFile::FaultType::QUERY_DATABASE, err, "update file fail"});
1768 return;
1769 }
1770 inoPtr->stat.st_size = childInfo.size;
1771 inoPtr->stat.st_mtime = childInfo.mtime / MILLISECOND_TO_SECONDS_TIMES;
1772 }
1773
UpdateCloudStore(CloudDiskFuseData * data,const std::string & fileName,const std::string & parentCloudId,shared_ptr<CloudDiskInode> inoPtr,bool isWrite)1774 static void UpdateCloudStore(CloudDiskFuseData *data, const std::string &fileName, const std::string &parentCloudId,
1775 shared_ptr<CloudDiskInode> inoPtr, bool isWrite)
1776 {
1777 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1778 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1779 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1780 int32_t dirtyType;
1781 int res = rdbStore->GetDirtyType(inoPtr->cloudId, dirtyType);
1782 if (res != 0) {
1783 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::RELEASE,
1784 CloudFile::FaultType::QUERY_DATABASE, res, "get file status fail, err: " + std::to_string(res)});
1785 }
1786 res = rdbStore->Write(fileName, parentCloudId, inoPtr->cloudId);
1787 if (res != 0) {
1788 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::RELEASE,
1789 CloudFile::FaultType::MODIFY_DATABASE, res, "write file fail"});
1790 }
1791 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1792 NotifyOpsType::DAEMON_WRITE, inoPtr}, {dirtyType, false, isWrite});
1793 UpdateCloudDiskInode(rdbStore, inoPtr);
1794 }
1795
UpdateCacheDentrySize(CloudDiskFuseData * data,fuse_ino_t ino)1796 static int32_t UpdateCacheDentrySize(CloudDiskFuseData *data, fuse_ino_t ino)
1797 {
1798 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1799 if (inoPtr == nullptr) {
1800 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::WRITE,
1801 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
1802 return EINVAL;
1803 }
1804 string filePath = CloudFileUtils::GetLocalFilePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
1805 struct stat statInfo {};
1806 int32_t ret = stat(filePath.c_str(), &statInfo);
1807 if (ret != 0) {
1808 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName, CloudFile::FaultOperation::WRITE,
1809 CloudFile::FaultType::FILE, errno, "filePath " + GetAnonyString(filePath) + " is invalid"});
1810 return errno;
1811 }
1812 MetaBase metaBase(inoPtr->fileName);
1813 metaBase.mtime = static_cast<uint64_t>(CloudFileUtils::Timespec2Milliseconds(statInfo.st_mtim));
1814 metaBase.size = static_cast<uint64_t>(statInfo.st_size);
1815 auto callback = [&metaBase] (MetaBase &m) {
1816 m.size = metaBase.size;
1817 m.mtime = metaBase.mtime;
1818 };
1819 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
1820 static_cast<int64_t>(inoPtr->parent));
1821 if (parentInode == nullptr) {
1822 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::WRITE,
1823 CloudFile::FaultType::INODE_FILE, EINVAL, "fail to find parent inode"});
1824 return EINVAL;
1825 }
1826 string parentCloudId = parentInode->cloudId;
1827 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId, inoPtr->bundleName, parentCloudId);
1828 ret = metaFile->DoChildUpdate(inoPtr->fileName, callback);
1829 if (ret != 0) {
1830 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::WRITE,
1831 CloudFile::FaultType::DENTRY_FILE, ret, "update new dentry failed, ret = " + std::to_string(ret)});
1832 return ret;
1833 }
1834 inoPtr->stat.st_size = static_cast<decltype(inoPtr->stat.st_size)>(metaBase.size);
1835 inoPtr->stat.st_mtime =
1836 static_cast<decltype(inoPtr->stat.st_mtime)>(metaBase.mtime / MILLISECOND_TO_SECONDS_TIMES);
1837 return 0;
1838 }
1839
WriteBuf(fuse_req_t req,fuse_ino_t ino,struct fuse_bufvec * bufv,off_t off,struct fuse_file_info * fi)1840 void FileOperationsCloud::WriteBuf(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv,
1841 off_t off, struct fuse_file_info *fi)
1842 {
1843 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1844 struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(bufv));
1845 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1846 auto filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
1847 if (filePtr == nullptr) {
1848 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::WRITE,
1849 CloudFile::FaultType::DRIVERKIT, EINVAL, "file not found"});
1850 fuse_reply_err(req, EINVAL);
1851 return;
1852 }
1853 if (filePtr->type != CLOUD_DISK_FILE_TYPE_LOCAL) {
1854 fuse_reply_err(req, EINVAL);
1855 LOGE("write on cloud file not supported");
1856 return;
1857 }
1858 out_buf.buf[0].flags = (fuse_buf_flags)(FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK);
1859 out_buf.buf[0].fd = filePtr->fd;
1860 out_buf.buf[0].pos = off;
1861 int res = fuse_buf_copy(&out_buf, bufv, (fuse_buf_copy_flags)(0));
1862 if (res < 0) {
1863 fuse_reply_err(req, -res);
1864 } else {
1865 if (filePtr != nullptr) { filePtr->fileDirty = CLOUD_DISK_FILE_WRITE; }
1866 int32_t ret = UpdateCacheDentrySize(data, ino);
1867 if (ret != 0) {
1868 LOGE("write size in cache and dentry fail, ret = %{public}d", ret);
1869 }
1870 fuse_reply_write(req, (size_t) res);
1871 }
1872 }
1873
UploadLocalFile(CloudDiskFuseData * data,const std::string & fileName,const std::string & parentCloudId,shared_ptr<CloudDiskInode> inoPtr,bool isWrite)1874 static void UploadLocalFile(CloudDiskFuseData *data, const std::string &fileName, const std::string &parentCloudId,
1875 shared_ptr<CloudDiskInode> inoPtr, bool isWrite)
1876 {
1877 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1878 MetaBase metaBase(fileName);
1879 auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId, inoPtr->bundleName, parentCloudId);
1880 int32_t ret = metaFile->DoLookup(metaBase);
1881 if (ret != 0) {
1882 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName, CloudFile::FaultOperation::RELEASE,
1883 CloudFile::FaultType::DENTRY_FILE, ret, "local file get location from dentryfile fail, ret = " +
1884 std::to_string(ret)});
1885 } else if (metaBase.position == LOCAL || isWrite) {
1886 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1887 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1888 int32_t dirtyType;
1889 ret = rdbStore->GetDirtyType(inoPtr->cloudId, dirtyType);
1890 if (ret != 0) {
1891 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName,
1892 CloudFile::FaultOperation::RELEASE, CloudFile::FaultType::DRIVERKIT_DATABASE, ret,
1893 "get file status fail, err: " + std::to_string(ret)});
1894 }
1895 ret = rdbStore->Write(fileName, parentCloudId, inoPtr->cloudId);
1896 if (ret != 0) {
1897 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::RELEASE,
1898 CloudFile::FaultType::DRIVERKIT_DATABASE, ret, "write file fail"});
1899 }
1900 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1901 NotifyOpsType::DAEMON_WRITE, inoPtr}, {dirtyType, false, isWrite});
1902 UpdateCloudDiskInode(rdbStore, inoPtr);
1903 }
1904 }
1905
HandleLocalClose(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr,shared_ptr<CloudDiskFile> filePtr,const string & parentCloudId)1906 static int32_t HandleLocalClose(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr,
1907 shared_ptr<CloudDiskFile> filePtr, const string &parentCloudId)
1908 {
1909 struct stat statInfo {};
1910 if (fstat(filePtr->fd, &statInfo) != 0) {
1911 LOGE("fstat failed, errno %{public}d", errno);
1912 filePtr->refCount++;
1913 return errno;
1914 }
1915 close(filePtr->fd);
1916 filePtr->readSession = nullptr;
1917 auto editedTime = static_cast<uint64_t>(CloudFileUtils::Timespec2Milliseconds(statInfo.st_mtim));
1918 bool isWrite = ((filePtr->fileDirty == CLOUD_DISK_FILE_WRITE) || (editedTime > filePtr->mtime));
1919 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1920 if (filePtr->fileDirty != CLOUD_DISK_FILE_UNKNOWN) {
1921 UpdateCloudStore(data, inoPtr->fileName, parentCloudId, inoPtr, isWrite);
1922 } else if (filePtr->isWriteOpen) {
1923 UploadLocalFile(data, inoPtr->fileName, parentCloudId, inoPtr, isWrite);
1924 }
1925 return 0;
1926 }
1927
HandleRelease(std::shared_ptr<CloudDiskFile> filePtr,std::shared_ptr<CloudDiskInode> inoPtr,CloudDiskFuseData * data)1928 static void HandleRelease(std::shared_ptr<CloudDiskFile> filePtr, std::shared_ptr<CloudDiskInode> inoPtr,
1929 CloudDiskFuseData *data)
1930 {
1931 std::unique_lock<std::shared_mutex> lck(inoPtr->sessionLock);
1932 filePtr->readSession->sessionCount--;
1933 if (filePtr->readSession->sessionCount == 0) {
1934 bool res = filePtr->readSession->Close(false);
1935 if (!res) {
1936 LOGE("close error");
1937 }
1938 string path = CloudFileUtils::GetLocalDKCachePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
1939 ErasePathCache(path, data);
1940 filePtr->readSession = nullptr;
1941 LOGD("readSession released");
1942 }
1943 }
1944
Release(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)1945 void FileOperationsCloud::Release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
1946 {
1947 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1948 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1949 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1950 if (inoPtr == nullptr) {
1951 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::RELEASE,
1952 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
1953 return (void)fuse_reply_err(req, EINVAL);
1954 }
1955 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
1956 static_cast<int64_t>(inoPtr->parent));
1957 if (parentInode == nullptr) {
1958 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::RELEASE,
1959 CloudFile::FaultType::INODE_FILE, EINVAL, "fail to find parent inode"});
1960 return (void)fuse_reply_err(req, EINVAL);
1961 }
1962 string parentCloudId = parentInode->cloudId;
1963 auto filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
1964 if (filePtr == nullptr) {
1965 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{parentInode->bundleName,
1966 CloudFile::FaultOperation::RELEASE, CloudFile::FaultType::DRIVERKIT, EINVAL, "file not found"});
1967 return (void)fuse_reply_err(req, EINVAL);
1968 }
1969 filePtr->refCount--;
1970 if (filePtr->refCount == 0) {
1971 if (filePtr->type == CLOUD_DISK_FILE_TYPE_LOCAL) {
1972 auto ret = HandleLocalClose(req, inoPtr, filePtr, parentCloudId);
1973 if (ret) {
1974 return (void)fuse_reply_err(req, ret);
1975 }
1976 } else if (filePtr->type == CLOUD_DISK_FILE_TYPE_CLOUD && filePtr->readSession != nullptr) {
1977 HandleRelease(filePtr, inoPtr, data);
1978 }
1979 FileOperationsHelper::PutCloudDiskFile(data, filePtr, fi->fh);
1980 }
1981 fuse_inval(data->se, inoPtr->parent, ino, inoPtr->fileName);
1982 fuse_reply_err(req, 0);
1983 }
1984
HandleTruncateError(shared_ptr<CloudDiskInode> inoPtr,shared_ptr<CloudDiskRdbStore> rdbStore,shared_ptr<CloudDiskInode> parentInode,fuse_req_t req)1985 void HandleTruncateError(shared_ptr<CloudDiskInode> inoPtr, shared_ptr<CloudDiskRdbStore> rdbStore,
1986 shared_ptr<CloudDiskInode> parentInode, fuse_req_t req)
1987 {
1988 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName,
1989 CloudFile::FaultOperation::SETATTR, CloudFile::FaultType::FILE, errno, "truncate failed, err: " +
1990 std::to_string(errno)});
1991 int res = rdbStore->SetAttr(inoPtr->fileName, parentInode->cloudId, inoPtr->cloudId, inoPtr->stat.st_size);
1992 if (res != 0) {
1993 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName,
1994 CloudFile::FaultOperation::SETATTR, CloudFile::FaultType::DATABASE, res,
1995 "update rdb size failed, res: " + std::to_string(res)});
1996 fuse_reply_err(req, EINVAL);
1997 } else {
1998 fuse_reply_err(req, errno);
1999 }
2000 }
2001
FuseFileTruncate(struct fuse_file_info * fi,struct CloudDiskFuseData * data,shared_ptr<CloudDiskInode> inoPtr,fuse_req_t req,struct stat * attr)2002 std::optional<int32_t> FuseFileTruncate(struct fuse_file_info* fi, struct CloudDiskFuseData* data,
2003 shared_ptr<CloudDiskInode> inoPtr, fuse_req_t req, struct stat *attr)
2004 {
2005 int32_t res = -1;
2006 if (fi) {
2007 auto filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
2008 if (filePtr == nullptr) {
2009 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName,
2010 CloudFile::FaultOperation::SETATTR, CloudFile::FaultType::DRIVERKIT, EINVAL, "file not found"});
2011 fuse_reply_err(req, EINVAL);
2012 return std::nullopt;
2013 }
2014 res = ftruncate(filePtr->fd, attr->st_size);
2015 } else {
2016 string path = CloudFileUtils::GetLocalFilePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
2017 res = truncate(path.c_str(), attr->st_size);
2018 }
2019 return res;
2020 }
2021
SetAttr(fuse_req_t req,fuse_ino_t ino,struct stat * attr,int valid,struct fuse_file_info * fi)2022 void FileOperationsCloud::SetAttr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
2023 int valid, struct fuse_file_info *fi)
2024 {
2025 if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
2026 LOGE("wait move error");
2027 return (void) fuse_reply_err(req, EBUSY);
2028 }
2029 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
2030 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
2031 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
2032 if (inoPtr == nullptr) {
2033 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::SETATTR,
2034 CloudFile::FaultType::INODE_FILE, EINVAL, "get an invalid inode!"});
2035 return (void) fuse_reply_err(req, EINVAL);
2036 }
2037 auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
2038 static_cast<int64_t>(inoPtr->parent));
2039 if (parentInode == nullptr) {
2040 LOGE("parent inode not found");
2041 fuse_reply_err(req, EINVAL);
2042 return;
2043 }
2044 if (static_cast<unsigned int>(valid) & FUSE_SET_ATTR_SIZE) {
2045 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
2046 auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
2047 int32_t res = rdbStore->SetAttr(inoPtr->fileName, parentInode->cloudId, inoPtr->cloudId, attr->st_size);
2048 if (res != 0) {
2049 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{inoPtr->bundleName,
2050 CloudFile::FaultOperation::SETATTR, CloudFile::FaultType::DATABASE, res,
2051 "update rdb size failed, res: " + std::to_string(res)});
2052 return (void) fuse_reply_err(req, EINVAL);
2053 }
2054
2055 auto ret = FuseFileTruncate(fi, data, inoPtr, req, attr);
2056 if (!ret.has_value()) {
2057 return;
2058 }
2059
2060 if (ret.value() == -1) {
2061 HandleTruncateError(inoPtr, rdbStore, parentInode, req);
2062 return;
2063 }
2064 UpdateCloudDiskInode(rdbStore, inoPtr);
2065 }
2066 CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
2067 NotifyOpsType::DAEMON_SETATTR, inoPtr});
2068 fuse_reply_attr(req, &inoPtr->stat, 0);
2069 }
2070
Lseek(fuse_req_t req,fuse_ino_t ino,off_t off,int whence,struct fuse_file_info * fi)2071 void FileOperationsCloud::Lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
2072 struct fuse_file_info *fi)
2073 {
2074 HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
2075 auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
2076 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
2077 if (inoPtr == nullptr) {
2078 LOGE("get an invalid inode!");
2079 fuse_reply_err(req, EINVAL);
2080 return;
2081 }
2082 shared_ptr<CloudDiskFile> filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
2083 if (filePtr == nullptr) {
2084 fuse_reply_err(req, EINVAL);
2085 LOGE("file not found");
2086 return;
2087 }
2088 if (filePtr->type != CLOUD_DISK_FILE_TYPE_LOCAL) {
2089 fuse_reply_err(req, ENOSYS);
2090 LOGE("lseek on cloud file not supported");
2091 return;
2092 }
2093 off_t res = lseek(filePtr->fd, off, whence);
2094 if (res != -1)
2095 fuse_reply_lseek(req, res);
2096 else
2097 fuse_reply_err(req, errno);
2098 }
2099
Ioctl(fuse_req_t req,fuse_ino_t ino,int cmd,void * arg,struct fuse_file_info * fi,unsigned flags,const void * inBuf,size_t inBufsz,size_t outBufsz)2100 void FileOperationsCloud::Ioctl(fuse_req_t req, fuse_ino_t ino, int cmd, void *arg, struct fuse_file_info *fi,
2101 unsigned flags, const void *inBuf, size_t inBufsz, size_t outBufsz)
2102 {
2103 if (static_cast<unsigned int>(cmd) == HMDFS_IOC_COPY_FILE) {
2104 auto dataReq = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
2105 auto inoPtr = FileOperationsHelper::FindCloudDiskInode(dataReq, static_cast<int64_t>(ino));
2106 if (inoPtr == nullptr) {
2107 LOGE("Failed to find inode for cloud disk");
2108 fuse_reply_err(req, EINVAL);
2109 return;
2110 }
2111 if (S_ISDIR(inoPtr->stat.st_mode)) {
2112 LOGE("Dir is not supported");
2113 fuse_reply_err(req, ENOSYS);
2114 return;
2115 }
2116
2117 const struct CloudDiskCopy *dataCopy = reinterpret_cast<const struct CloudDiskCopy *>(inBuf);
2118 std::string dest(dataCopy->destPath);
2119 std::string destPath = CloudFileUtils::GetRealPath(dest);
2120 DatabaseManager &databaseManager = DatabaseManager::GetInstance();
2121 shared_ptr<CloudDiskRdbStore> rdbStore =
2122 databaseManager.GetRdbStore(inoPtr->bundleName, dataReq->userId);
2123
2124 std::string destCloudId;
2125 int32_t ret = GenerateCloudId(dataReq->userId, destCloudId, inoPtr->bundleName);
2126 if (ret != 0) {
2127 LOGE("Failed generate cloud id, ret: %{public}d", ret);
2128 fuse_reply_err(req, ENOSYS);
2129 return;
2130 }
2131 if ((rdbStore->CopyFile(inoPtr->cloudId, destCloudId, inoPtr->bundleName, dataReq->userId, destPath) != 0)) {
2132 fuse_reply_err(req, EIO);
2133 return;
2134 }
2135 fuse_reply_ioctl(req, 0, NULL, 0);
2136 } else {
2137 LOGE("Invalid argument, cmd is not supported");
2138 fuse_reply_err(req, EINVAL);
2139 return;
2140 }
2141 }
2142 } // namespace CloudDisk
2143 } // namespace FileManagement
2144 } // namespace OHOS
2145