• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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