• 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 "hitrace_meter.h"
38 #include "securec.h"
39 #include "utils_log.h"
40 
41 namespace OHOS {
42 namespace FileManagement {
43 namespace CloudDisk {
44 using namespace std;
45 using namespace CloudFile;
46 enum XATTR_CODE {
47     ERROR_CODE = -1,
48     HMDFS_PERMISSION,
49     CLOUD_LOCATION,
50     CLOUD_RECYCLE,
51     IS_FAVORITE,
52     HAS_THM
53 };
54 namespace {
55     static const uint32_t STAT_NLINK_REG = 1;
56     static const uint32_t STAT_NLINK_DIR = 2;
57     static const uint32_t CLOUD_FILE_LAYER = 2;
58     static const uint32_t USER_LOCAL_ID_OFFSET = 100;
59     static const uint32_t STAT_MODE_REG = 0660;
60     static const uint32_t STAT_MODE_DIR = 0771;
61     static const uint32_t MILLISECOND_TO_SECONDS_TIMES = 1000;
62     static const uint32_t RECYCLE_LOCAL_ID = 4;
63     static const string FILE_LOCAL = "1";
64     static const string ROOT_CLOUD_ID = "rootId";
65     static const string RECYCLE_NAME = ".trash";
66     static const uint64_t UNKNOWN_INODE_ID = 0;
67     static const std::string FILEMANAGER_KEY = "persist.kernel.bundle_name.filemanager";
68     static const unsigned int MAX_READ_SIZE = 4 * 1024 * 1024;
69 }
70 
InitInodeAttr(struct CloudDiskFuseData * data,fuse_ino_t parent,struct CloudDiskInode * childInode,const MetaBase & metaBase,const int64_t & inodeId)71 static void InitInodeAttr(struct CloudDiskFuseData *data, fuse_ino_t parent,
72     struct CloudDiskInode *childInode, const MetaBase &metaBase, const int64_t &inodeId)
73 {
74     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
75     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
76         static_cast<int64_t>(parent));
77     if (parentInode == nullptr) {
78         LOGE("parent inode not found");
79         return;
80     }
81     childInode->stat = parentInode->stat;
82     childInode->stat.st_ino = static_cast<uint64_t>(inodeId);
83     childInode->stat.st_mtime = metaBase.mtime / MILLISECOND_TO_SECONDS_TIMES;
84     childInode->stat.st_atime = metaBase.atime / MILLISECOND_TO_SECONDS_TIMES;
85 
86     childInode->bundleName = parentInode->bundleName;
87     childInode->fileName = metaBase.name;
88     childInode->layer = FileOperationsHelper::GetNextLayer(parentInode, parent);
89     childInode->parent = parent;
90     childInode->cloudId = metaBase.cloudId;
91     childInode->ops = make_shared<FileOperationsCloud>();
92 
93     if (S_ISDIR(metaBase.mode)) {
94         childInode->stat.st_mode = S_IFDIR | STAT_MODE_DIR;
95         childInode->stat.st_nlink = STAT_NLINK_DIR;
96     } else {
97         childInode->stat.st_mode = S_IFREG | STAT_MODE_REG;
98         childInode->stat.st_nlink = STAT_NLINK_REG;
99         childInode->stat.st_size = metaBase.size;
100     }
101 }
102 
InitFileAttr(struct CloudDiskFuseData * data,struct fuse_file_info * fi)103 static shared_ptr<CloudDiskFile> InitFileAttr(struct CloudDiskFuseData *data, struct fuse_file_info *fi)
104 {
105     std::unique_lock<std::shared_mutex> wLock(data->fileLock, std::defer_lock);
106     shared_ptr<CloudDiskFile> filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
107     if (filePtr == nullptr) {
108         filePtr = make_shared<CloudDiskFile>();
109         wLock.lock();
110         data->fileCache[fi->fh] = filePtr;
111         wLock.unlock();
112     }
113     filePtr->refCount++;
114     return filePtr;
115 }
116 
InitLocalIdCache(struct CloudDiskFuseData * data,const std::string & key,const int64_t val)117 static void InitLocalIdCache(struct CloudDiskFuseData *data, const std::string &key, const int64_t val)
118 {
119     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
120     std::unique_lock<std::shared_mutex> wLock(data->localIdLock, std::defer_lock);
121     int64_t localId = FileOperationsHelper::FindLocalId(data, key);
122     if (localId == -1) {
123         wLock.lock();
124         data->localIdCache[key] = val;
125         wLock.unlock();
126     }
127 }
128 
LookUpRecycleBin(struct CloudDiskFuseData * data,fuse_ino_t parent,shared_ptr<CloudDiskInode> parentInode,struct fuse_entry_param * e)129 static void LookUpRecycleBin(struct CloudDiskFuseData *data, fuse_ino_t parent,
130     shared_ptr<CloudDiskInode> parentInode, struct fuse_entry_param *e)
131 {
132     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
133     std::unique_lock<std::shared_mutex> cacheWLock(data->cacheLock, std::defer_lock);
134     auto child = FileOperationsHelper::FindCloudDiskInode(data, RECYCLE_LOCAL_ID);
135     if (child == nullptr) {
136         child = make_shared<CloudDiskInode>();
137         child->stat = parentInode->stat;
138         child->stat.st_ino = RECYCLE_LOCAL_ID;
139         child->bundleName = parentInode->bundleName;
140         child->fileName = RECYCLE_NAME;
141         child->layer = FileOperationsHelper::GetNextLayer(parentInode, parent);
142         child->parent = parent;
143         child->cloudId = RECYCLE_CLOUD_ID;
144         child->ops = make_shared<FileOperationsCloud>();
145         child->stat.st_mode = S_IFDIR | STAT_MODE_DIR;
146         child->stat.st_nlink = STAT_NLINK_DIR;
147         cacheWLock.lock();
148         data->inodeCache[RECYCLE_LOCAL_ID] = child;
149         cacheWLock.unlock();
150     }
151     e->ino = static_cast<fuse_ino_t>(RECYCLE_LOCAL_ID);
152     FileOperationsHelper::GetInodeAttr(child, &e->attr);
153 }
154 
UpdateChildCache(struct CloudDiskFuseData * data,int64_t localId,shared_ptr<CloudDiskInode> child)155 static shared_ptr<CloudDiskInode> UpdateChildCache(struct CloudDiskFuseData *data, int64_t localId,
156     shared_ptr<CloudDiskInode> child)
157 {
158     std::unique_lock<std::shared_mutex> cacheWLock(data->cacheLock, std::defer_lock);
159     std::unique_lock<std::shared_mutex> localIdWLock(data->localIdLock, std::defer_lock);
160     if (child == nullptr) {
161         child = make_shared<CloudDiskInode>();
162         cacheWLock.lock();
163         data->inodeCache[localId] = child;
164         cacheWLock.unlock();
165     } else {
166         auto old_key = std::to_string(child->parent) + child->fileName;
167         localIdWLock.lock();
168         data->localIdCache.erase(old_key);
169         localIdWLock.unlock();
170     }
171     return child;
172 }
173 
LookupRecycledFile(struct CloudDiskFuseData * data,const char * name,const std::string bundleName,struct fuse_entry_param * e)174 static int32_t LookupRecycledFile(struct CloudDiskFuseData *data, const char *name,
175     const std::string bundleName, struct fuse_entry_param *e)
176 {
177     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
178     MetaBase metaBase(name);
179     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId, bundleName,
180         RECYCLE_CLOUD_ID);
181     int ret = metaFile->DoLookup(metaBase);
182     if (ret != 0) {
183         LOGE("file %{public}s not found in recyclebin", GetAnonyString(name).c_str());
184         return EINVAL;
185     }
186     int64_t inodeId = static_cast<int64_t>(CloudFileUtils::DentryHash(metaBase.cloudId));
187     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, inodeId);
188     if (inoPtr == nullptr) {
189         string nameStr = name;
190         size_t lastSlash = nameStr.find_last_of("_");
191         metaBase.name = nameStr.substr(0, lastSlash);
192         inoPtr = UpdateChildCache(data, inodeId, inoPtr);
193         inoPtr->refCount++;
194         InitInodeAttr(data, RECYCLE_LOCAL_ID, inoPtr.get(), metaBase, inodeId);
195         inoPtr->parent = UNKNOWN_INODE_ID;
196     }
197     e->ino = static_cast<fuse_ino_t>(inodeId);
198     FileOperationsHelper::GetInodeAttr(inoPtr, &e->attr);
199     return 0;
200 }
201 
DoCloudLookup(fuse_req_t req,fuse_ino_t parent,const char * name,struct fuse_entry_param * e)202 static int32_t DoCloudLookup(fuse_req_t req, fuse_ino_t parent, const char *name,
203                              struct fuse_entry_param *e)
204 {
205     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
206     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
207     if (parent == FUSE_ROOT_ID) {
208         LOGE("cloud file operations should not get a fuse root inode");
209         return EINVAL;
210     }
211 
212     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
213         static_cast<int64_t>(parent));
214     if (parentInode == nullptr) {
215         LOGE("fail to find parent inode");
216         return EINVAL;
217     }
218     if (name == RECYCLE_NAME) {
219         LookUpRecycleBin(data, parent, parentInode, e);
220         return 0;
221     } else if (parent == RECYCLE_LOCAL_ID) {
222         int32_t ret = LookupRecycledFile(data, name, parentInode->bundleName, e);
223         if (ret != 0) {
224             LOGE("fail to lookup recycledfile");
225             return ret;
226         }
227         return 0;
228     }
229     MetaBase metaBase(name);
230     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId, parentInode->bundleName,
231         parentInode->cloudId);
232     int32_t ret = metaFile->DoLookup(metaBase);
233     if (ret != 0) {
234         LOGE("lookup dentry failed, name:%{public}s, ret = %{public}d", GetAnonyString(name).c_str(), ret);
235         return ENOENT;
236     }
237     string key = std::to_string(parent) + name;
238     int64_t inodeId = static_cast<int64_t>(CloudFileUtils::DentryHash(metaBase.cloudId));
239     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, inodeId);
240     auto child = UpdateChildCache(data, inodeId, inoPtr);
241     child->refCount++;
242     InitInodeAttr(data, parent, child.get(), metaBase, inodeId);
243     InitLocalIdCache(data, key, inodeId);
244     e->ino = static_cast<fuse_ino_t>(inodeId);
245     FileOperationsHelper::GetInodeAttr(child, &e->attr);
246     return 0;
247 }
248 
Lookup(fuse_req_t req,fuse_ino_t parent,const char * name)249 void FileOperationsCloud::Lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
250 {
251     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
252     struct fuse_entry_param e;
253     e.attr_timeout = 1.0;
254     e.entry_timeout = 1.0;
255     int32_t err = DoCloudLookup(req, parent, name, &e);
256     if (err) {
257         fuse_reply_err(req, err);
258     } else {
259         fuse_reply_entry(req, &e);
260     }
261 }
262 
Access(fuse_req_t req,fuse_ino_t ino,int mask)263 void FileOperationsCloud::Access(fuse_req_t req, fuse_ino_t ino, int mask)
264 {
265     LOGI("Access operation is not supported!");
266     fuse_reply_err(req, ENOSYS);
267 }
268 
GetAttr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)269 void FileOperationsCloud::GetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
270 {
271     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
272     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
273     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
274     if (inoPtr == nullptr) {
275         LOGE("inode not found");
276         fuse_reply_err(req, EINVAL);
277         return;
278     }
279     fuse_reply_attr(req, &inoPtr->stat, 0);
280 }
281 
HandleCloudError(fuse_req_t req,CloudError error)282 static bool HandleCloudError(fuse_req_t req, CloudError error)
283 {
284     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
285     if (error == CloudError::CK_NO_ERROR) {
286         return false;
287     }
288     if (error == CloudError::CK_NETWORK_ERROR) {
289         LOGE("network error");
290         fuse_reply_err(req, ENOTCONN);
291     } else if (error == CloudError::CK_SERVER_ERROR) {
292         LOGE("server error");
293         fuse_reply_err(req, EIO);
294     } else if (error == CloudError::CK_LOCAL_ERROR) {
295         LOGE("local error");
296         fuse_reply_err(req, EINVAL);
297     } else {
298         LOGE("Unknow error");
299         fuse_reply_err(req, EIO);
300     }
301     return true;
302 }
303 
GetDatabase(int32_t userId,const string & bundleName)304 static shared_ptr<CloudDatabase> GetDatabase(int32_t userId, const string &bundleName)
305 {
306     auto instance = CloudFile::CloudFileKit::GetInstance();
307     if (instance == nullptr) {
308         LOGE("get cloud file helper instance failed");
309         return nullptr;
310     }
311 
312     if (AccountStatus::IsNeedCleanCache()) {
313         auto ret = instance->CleanCloudUserInfo(userId);
314         if (ret != 0) {
315             return nullptr;
316         }
317         LOGI("execute clean cloud user info success");
318     }
319 
320     auto database = instance->GetCloudDatabase(userId, bundleName);
321     if (database == nullptr) {
322         LOGE("get cloud file kit database fail");
323         return nullptr;
324     }
325     return database;
326 }
327 
CloudOpen(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr,struct fuse_file_info * fi,string path)328 static void CloudOpen(fuse_req_t req,
329     shared_ptr<CloudDiskInode> inoPtr, struct fuse_file_info *fi, string path)
330 {
331     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
332     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
333     auto filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
334     if (filePtr == nullptr) {
335         filePtr = InitFileAttr(data, fi);
336     }
337     auto database = GetDatabase(data->userId, inoPtr->bundleName);
338     if (!database) {
339         fuse_reply_err(req, EPERM);
340         LOGE("database is null");
341         return;
342     }
343 
344     if (filePtr->readSession) {
345         filePtr->type = CLOUD_DISK_FILE_TYPE_CLOUD;
346         fuse_reply_open(req, fi);
347         return;
348     }
349 
350     string cloudId = inoPtr->cloudId;
351     LOGD("cloudId: %s", cloudId.c_str());
352     filePtr->readSession = database->NewAssetReadSession("file", cloudId, "content", path);
353     if (filePtr->readSession) {
354         auto error = filePtr->readSession->InitSession();
355         if (!HandleCloudError(req, error)) {
356             filePtr->type = CLOUD_DISK_FILE_TYPE_CLOUD;
357             fuse_reply_open(req, fi);
358         } else {
359             filePtr->readSession = nullptr;
360             LOGE("open fail");
361         }
362     } else {
363         fuse_reply_err(req, EPERM);
364         LOGE("readSession is null");
365     }
366     return;
367 }
368 
Open(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)369 void FileOperationsCloud::Open(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
370 {
371     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
372         LOGE("wait move error");
373         return (void) fuse_reply_err(req, EBUSY);
374     }
375     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
376     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
377     std::unique_lock<std::shared_mutex> wLock(data->fileIdLock, std::defer_lock);
378     wLock.lock();
379     data->fileId++;
380     fi->fh = static_cast<uint64_t>(data->fileId);
381     wLock.unlock();
382     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
383     if (inoPtr == nullptr) {
384         LOGE("inode not found");
385         fuse_reply_err(req, EINVAL);
386         return;
387     }
388     string path = CloudFileUtils::GetLocalFilePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
389     unsigned int flags = static_cast<unsigned int>(fi->flags);
390     if (access(path.c_str(), F_OK) == 0) {
391         if ((flags & O_ACCMODE) & O_WRONLY) {
392             flags &= ~O_WRONLY;
393             flags |= O_RDWR;
394         }
395         if (flags & O_APPEND) {
396             flags &= ~O_APPEND;
397         }
398         if (flags & O_DIRECT) {
399             flags &= ~O_DIRECT;
400         }
401         int32_t fd = open(path.c_str(), flags);
402         if (fd < 0) {
403             LOGE("open file failed path:%{public}s errno:%{public}d", GetAnonyString(path).c_str(), errno);
404             return (void) fuse_reply_err(req, errno);
405         }
406         auto filePtr = InitFileAttr(data, fi);
407         filePtr->type = CLOUD_DISK_FILE_TYPE_LOCAL;
408         filePtr->fd = fd;
409         filePtr->isWriteOpen = (flags & O_RDWR) | (flags & O_WRONLY);
410         fuse_reply_open(req, fi);
411     } else {
412         CloudOpen(req, inoPtr, fi, path);
413     }
414 }
415 
CreateLocalFile(const string & cloudId,const string & bundleName,int32_t userId,mode_t mode)416 static int32_t CreateLocalFile(const string &cloudId, const string &bundleName, int32_t userId, mode_t mode)
417 {
418     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
419     string bucketPath = CloudFileUtils::GetLocalBucketPath(cloudId, bundleName, userId);
420     string path = CloudFileUtils::GetLocalFilePath(cloudId, bundleName, userId);
421     if (access(bucketPath.c_str(), F_OK) != 0) {
422         if (mkdir(bucketPath.c_str(), STAT_MODE_DIR) != 0) {
423             LOGE("mkdir bucketpath failed :%{public}s err:%{public}d", GetAnonyString(bucketPath).c_str(), errno);
424             return -errno;
425         }
426     }
427     int32_t fd = open(path.c_str(), (mode & O_NOFOLLOW) | O_CREAT | O_RDWR, STAT_MODE_REG);
428     if (fd < 0) {
429         LOGE("create file failed :%{public}s err:%{public}d", GetAnonyString(path).c_str(), errno);
430         return -errno;
431     }
432     return fd;
433 }
434 
RemoveLocalFile(const string & path)435 void RemoveLocalFile(const string &path)
436 {
437     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
438     int32_t err = remove(path.c_str());
439     if (err != 0) {
440         LOGE("remove file %{public}s failed, error:%{public}d", GetAnonyString(path).c_str(), errno);
441     }
442 }
443 
GenerateCloudId(int32_t userId,string & cloudId,const string & bundleName)444 int32_t GenerateCloudId(int32_t userId, string &cloudId, const string &bundleName)
445 {
446     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
447     auto dkDatabasePtr = GetDatabase(userId, bundleName);
448     if (dkDatabasePtr == nullptr) {
449         LOGE("Failed to get database");
450         return ENOSYS;
451     }
452 
453     vector<std::string> ids;
454     auto ret = dkDatabasePtr->GenerateIds(1, ids);
455     if (ret != 0 || ids.size() == 0) {
456         return ENOSYS;
457     }
458     cloudId = ids[0];
459     return 0;
460 }
461 
GetParentUpload(shared_ptr<CloudDiskInode> parentInode,struct CloudDiskFuseData * data,bool & parentNoUpload)462 static int32_t GetParentUpload(shared_ptr<CloudDiskInode> parentInode, struct CloudDiskFuseData *data,
463                                bool &parentNoUpload)
464 {
465     auto grandparentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parentInode->parent));
466     if (grandparentInode == nullptr) {
467         LOGE("grandparentInode not found");
468         return EINVAL;
469     }
470     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
471         grandparentInode->bundleName, grandparentInode->cloudId);
472     MetaBase metaBase(parentInode->fileName);
473     auto ret = metaFile->DoLookup(metaBase);
474     if (ret != 0) {
475         LOGE("file %{public}s not found", parentInode->fileName.c_str());
476         return ret;
477     }
478     parentNoUpload = (metaBase.noUpload == NO_UPLOAD);
479     return 0;
480 }
481 
DoCreatFile(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode,struct fuse_entry_param & e)482 int32_t DoCreatFile(fuse_req_t req, fuse_ino_t parent, const char *name,
483                     mode_t mode, struct fuse_entry_param &e)
484 {
485     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
486     struct CloudDiskFuseData *data =
487         reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
488     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
489         static_cast<int64_t>(parent));
490     if (parentInode == nullptr) {
491         LOGE("parent inode not found");
492         return EINVAL;
493     }
494     string cloudId;
495     int32_t err = GenerateCloudId(data->userId, cloudId, parentInode->bundleName);
496     if (err != 0) {
497         LOGE("Failed to generate cloud id");
498         return -err;
499     }
500 
501     int32_t fd = CreateLocalFile(cloudId, parentInode->bundleName, data->userId, mode);
502     if (fd < 0) {
503         LOGD("Create local file failed error:%{public}d", fd);
504         return fd;
505     }
506 
507     string path = CloudFileUtils::GetLocalFilePath(cloudId, parentInode->bundleName, data->userId);
508 
509     bool noNeedUpload = false;
510     if (parentInode->cloudId != ROOT_CLOUD_ID) {
511         err = GetParentUpload(parentInode, data, noNeedUpload);
512         if (err != 0) {
513             LOGE("Failed to get parent no upload");
514             close(fd);
515             RemoveLocalFile(path);
516             return -err;
517         }
518     }
519 
520     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
521     shared_ptr<CloudDiskRdbStore> rdbStore =
522         databaseManager.GetRdbStore(parentInode->bundleName, data->userId);
523     err = rdbStore->Create(cloudId, parentInode->cloudId, name, noNeedUpload);
524     if (err != 0) {
525         close(fd);
526         RemoveLocalFile(path);
527         return -err;
528     }
529     err = DoCloudLookup(req, parent, name, &e);
530     if (err != 0) {
531         close(fd);
532         RemoveLocalFile(path);
533         return -err;
534     }
535     return fd;
536 }
537 
MkNod(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode,dev_t rdev)538 void FileOperationsCloud::MkNod(fuse_req_t req, fuse_ino_t parent, const char *name,
539                                 mode_t mode, dev_t rdev)
540 {
541     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
542         LOGE("wait move error");
543         return (void) fuse_reply_err(req, EBUSY);
544     }
545     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
546     struct fuse_entry_param e;
547     int32_t err = DoCreatFile(req, parent, name, mode, e);
548     if (err < 0) {
549         fuse_reply_err(req, -err);
550         return;
551     }
552     close(err);
553     fuse_reply_entry(req, &e);
554 }
555 
Create(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode,struct fuse_file_info * fi)556 void FileOperationsCloud::Create(fuse_req_t req, fuse_ino_t parent, const char *name,
557                                  mode_t mode, struct fuse_file_info *fi)
558 {
559     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
560         LOGE("wait move error");
561         return (void) fuse_reply_err(req, EBUSY);
562     }
563     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
564     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
565     struct fuse_entry_param e;
566     int32_t err = DoCreatFile(req, parent, name, mode, e);
567     if (err < 0) {
568         fuse_reply_err(req, -err);
569         return;
570     }
571     auto filePtr = InitFileAttr(data, fi);
572     std::unique_lock<std::shared_mutex> wLock(data->fileIdLock, std::defer_lock);
573     wLock.lock();
574     data->fileId++;
575     fi->fh = static_cast<uint64_t>(data->fileId);
576     wLock.unlock();
577     filePtr->fd = err;
578     filePtr->type = CLOUD_DISK_FILE_TYPE_LOCAL;
579     filePtr->fileDirty = CLOUD_DISK_FILE_CREATE;
580     fuse_reply_create(req, &e, fi);
581 }
582 
FindNextPos(const vector<CloudDiskFileInfo> & childInfos,off_t off)583 static size_t FindNextPos(const vector<CloudDiskFileInfo> &childInfos, off_t off)
584 {
585     for (size_t i = 0; i < childInfos.size(); i++) {
586         /* Find the first valid offset beyond @off */
587         if (childInfos[i].nextOff > off) {
588             return i + 1;
589         }
590     }
591     /* If @off is beyond all valid offset, then return the index after the last info */
592     if (!childInfos.empty() && childInfos.back().nextOff < off) {
593         return childInfos.size();
594     }
595     return 0;
596 }
597 
FindNextPos(const vector<MetaBase> & childInfos,off_t off)598 static size_t FindNextPos(const vector<MetaBase> &childInfos, off_t off)
599 {
600     for (size_t i = 0; i < childInfos.size(); i++) {
601         /* Find the first valid offset beyond @off */
602         if (childInfos[i].nextOff > off) {
603             return i + 1;
604         }
605     }
606     /* If @off is beyond all valid offset, then return the index after the last info */
607     if (!childInfos.empty() && childInfos.back().nextOff < off) {
608         return childInfos.size();
609     }
610     return 0;
611 }
612 
GetChildInfos(fuse_req_t req,fuse_ino_t ino,vector<CloudDiskFileInfo> & childInfos)613 static int32_t GetChildInfos(fuse_req_t req, fuse_ino_t ino, vector<CloudDiskFileInfo> &childInfos)
614 {
615     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
616     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
617     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
618     if (inoPtr == nullptr) {
619         LOGE("inode not found");
620         return EINVAL;
621     }
622     string parentCloudId = inoPtr->cloudId;
623 
624     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
625     shared_ptr<CloudDiskRdbStore> rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
626     int32_t err = rdbStore->ReadDir(parentCloudId, childInfos);
627     if (err != 0) {
628         LOGE("Readdir failed cloudId:%{public}s err:%{public}d", parentCloudId.c_str(), err);
629         return err;
630     }
631     return 0;
632 }
633 
634 template<typename T>
CloudSeekDir(fuse_req_t req,fuse_ino_t ino,off_t off,const std::vector<T> & childInfos)635 static size_t CloudSeekDir(fuse_req_t req, fuse_ino_t ino, off_t off,
636                            const std::vector<T> &childInfos)
637 {
638     if (off == 0 || childInfos.empty()) {
639         return 0;
640     }
641 
642     size_t i = 0;
643     for (; i < childInfos.size(); i++) {
644         if (childInfos[i].nextOff == off) {
645             /* Start position should be the index of next entry */
646             return i + 1;
647         }
648     }
649     if (i == childInfos.size()) {
650         /* The directory may changed recently, find the next valid index for this offset */
651         return FindNextPos(childInfos, off);
652     }
653 
654     return 0;
655 }
656 
657 template<typename T>
AddDirEntryToBuf(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,const std::vector<T> & childInfos)658 static void AddDirEntryToBuf(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
659     const std::vector<T> &childInfos)
660 {
661     size_t startPos = CloudSeekDir<T>(req, ino, off, childInfos);
662     string buf;
663     buf.resize(size);
664     if (childInfos.empty() || startPos == childInfos.size()) {
665         LOGW("empty buffer replied");
666         return (void)fuse_reply_buf(req, buf.c_str(), 0);
667     }
668 
669     size_t nextOff = 0;
670     size_t remain = size;
671     static const struct stat statInfoDir = { .st_mode = S_IFDIR | STAT_MODE_DIR };
672     static const struct stat statInfoReg = { .st_mode = S_IFREG | STAT_MODE_REG };
673     for (size_t i = startPos; i < childInfos.size(); i++) {
674         size_t alignSize = CloudDiskRdbUtils::FuseDentryAlignSize(childInfos[i].name.c_str());
675         if (alignSize > remain) {
676             break;
677         }
678         alignSize = fuse_add_direntry(req, &buf[nextOff], alignSize, childInfos[i].name.c_str(),
679             childInfos[i].mode != S_IFREG ? &statInfoDir : &statInfoReg,
680             off + static_cast<off_t>(nextOff) + static_cast<off_t>(alignSize));
681         nextOff += alignSize;
682         remain -= alignSize;
683     }
684     (void)fuse_reply_buf(req, buf.c_str(), size - remain);
685 }
686 
ReadDirForRecycle(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)687 static void ReadDirForRecycle(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
688                               struct fuse_file_info *fi)
689 {
690     int32_t err = -1;
691     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
692     auto inode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
693     if (inode == nullptr) {
694         LOGE("inode not found");
695         fuse_reply_err(req, EINVAL);
696         return;
697     }
698     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
699         inode->bundleName, RECYCLE_NAME);
700     std::vector<MetaBase> childInfos;
701     err = metaFile->LoadChildren(childInfos);
702     if (err != 0) {
703         LOGE("load children failed, err=%{public}d", err);
704         fuse_reply_err(req, EINVAL);
705         return;
706     }
707     size_t nextOff = 0;
708     for (size_t i = 0; i < childInfos.size(); ++i) {
709         size_t alignSize = CloudDiskRdbUtils::FuseDentryAlignSize(childInfos[i].name.c_str());
710         nextOff += alignSize;
711         childInfos[i].nextOff = static_cast<off_t>(nextOff);
712     }
713     AddDirEntryToBuf(req, ino, size, off, childInfos);
714 }
715 
ReadDir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)716 void FileOperationsCloud::ReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
717                                   struct fuse_file_info *fi)
718 {
719     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
720         LOGE("wait move error");
721         return (void) fuse_reply_err(req, EBUSY);
722     }
723     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
724     if (ino == RECYCLE_LOCAL_ID) {
725         ReadDirForRecycle(req, ino, size, off, fi);
726         return;
727     }
728 
729     vector<CloudDiskFileInfo> childInfos;
730     int32_t err = GetChildInfos(req, ino, childInfos);
731     if (err != 0) {
732         LOGE("failed to get child infos, err=%{public}d", err);
733         return (void)fuse_reply_err(req, err);
734     }
735     AddDirEntryToBuf(req, ino, size, off, childInfos);
736 }
737 
CheckXattr(const char * name)738 int32_t CheckXattr(const char *name)
739 {
740     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
741     LOGD("start CheckXattr name is:%{public}s", name);
742     if (CloudFileUtils::CheckIsHmdfsPermission(name)) {
743         return HMDFS_PERMISSION;
744     } else if (CloudFileUtils::CheckIsCloudLocation(name)) {
745         return CLOUD_LOCATION;
746     } else if (CloudFileUtils::CheckIsCloudRecycle(name)) {
747         return CLOUD_RECYCLE;
748     } else if (CloudFileUtils::CheckIsFavorite(name)) {
749         return IS_FAVORITE;
750     } else if (CloudFileUtils::CheckIsHasLCD(name) || CloudFileUtils::CheckIsHasTHM(name)) {
751         return HAS_THM;
752     } else {
753         LOGD("no definition Xattr name:%{public}s", name);
754         return ERROR_CODE;
755     }
756 }
757 
HandleCloudLocation(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)758 void HandleCloudLocation(fuse_req_t req, fuse_ino_t ino, const char *name,
759                          const char *value)
760 {
761     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
762     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
763     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
764     if (inoPtr == nullptr) {
765         fuse_reply_err(req, EINVAL);
766         LOGE("inode not found");
767         return;
768     }
769     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(inoPtr->parent));
770     if (parentInode == nullptr) {
771         LOGE("parent inode not found");
772         return (void) fuse_reply_err(req, EINVAL);
773     }
774     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
775     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
776     int32_t err = rdbStore->SetXAttr(inoPtr->cloudId, CLOUD_FILE_LOCATION, value, inoPtr->fileName,
777         parentInode->cloudId);
778     if (err != 0) {
779         LOGE("set cloud id fail %{public}d", err);
780         fuse_reply_err(req, EINVAL);
781         return;
782     }
783     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
784         NotifyOpsType::DAEMON_SETXATTR, inoPtr});
785     fuse_reply_err(req, 0);
786 }
787 
HandleCloudRecycle(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)788 void HandleCloudRecycle(fuse_req_t req, fuse_ino_t ino, const char *name,
789                         const char *value)
790 {
791     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
792     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
793     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
794     if (inoPtr == nullptr) {
795         fuse_reply_err(req, EINVAL);
796         LOGE("inode not found");
797         return;
798     }
799     string parentCloudId;
800     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
801     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(inoPtr->parent));
802     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
803     if (parentInode == nullptr) {
804         int32_t ret = rdbStore->GetParentCloudId(inoPtr->cloudId, parentCloudId);
805         if (ret != 0) {
806             fuse_reply_err(req, EINVAL);
807             LOGE("fail to get parentCloudId");
808             return;
809         }
810     } else {
811         parentCloudId = parentInode->cloudId;
812     }
813     int32_t ret = MetaFileMgr::GetInstance().CreateRecycleDentry(data->userId, inoPtr->bundleName);
814     if (ret != 0) {
815         fuse_reply_err(req, EINVAL);
816         LOGE("create recycle dentry failed");
817         return;
818     }
819     ret = rdbStore->SetXAttr(inoPtr->cloudId, CLOUD_CLOUD_RECYCLE_XATTR, value,
820         inoPtr->fileName, parentCloudId);
821     if (ret != 0) {
822         LOGE("set cloud id fail %{public}d", ret);
823         fuse_reply_err(req, EINVAL);
824         return;
825     }
826     int32_t val = std::stoi(value);
827     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
828         val == 0 ? NotifyOpsType::DAEMON_RESTORE : NotifyOpsType::DAEMON_RECYCLE, inoPtr});
829     fuse_reply_err(req, 0);
830 }
831 
HandleFavorite(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)832 void HandleFavorite(fuse_req_t req, fuse_ino_t ino, const char *name,
833                     const char *value)
834 {
835     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
836     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
837     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
838     if (inoPtr == nullptr) {
839         fuse_reply_err(req, EINVAL);
840         LOGE("inode not found");
841         return;
842     }
843     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
844     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
845     int32_t err = rdbStore->SetXAttr(inoPtr->cloudId, IS_FAVORITE_XATTR, value);
846     if (err != 0) {
847         LOGE("set cloud id fail %{public}d", err);
848         fuse_reply_err(req, EINVAL);
849         return;
850     }
851     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
852         NotifyOpsType::DAEMON_SETXATTR, inoPtr});
853     fuse_reply_err(req, 0);
854 }
855 
HandleHasTHM(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)856 void HandleHasTHM(fuse_req_t req, fuse_ino_t ino, const char *name,
857                   const char *value)
858 {
859     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
860     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
861     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
862     if (inoPtr == nullptr) {
863         fuse_reply_err(req, EINVAL);
864         std::string errMsg = "inode not found";
865             CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{"", CloudFile::FaultOperation::SETATTR,
866                 CloudFile::FaultType::DENTRY_FILE, EINVAL, errMsg});
867         return;
868     }
869     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
870     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
871     int32_t err = rdbStore->SetXAttr(inoPtr->cloudId, name, value);
872     if (err != 0) {
873         std::string errMsg = "set has thm fail " + to_string(err);
874             CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{inoPtr->bundleName, CloudFile::FaultOperation::SETATTR,
875                 CloudFile::FaultType::DENTRY_FILE, EINVAL, errMsg});
876         fuse_reply_err(req, EINVAL);
877         return;
878     }
879     fuse_reply_err(req, 0);
880 }
881 
HandleExtAttribute(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value)882 void HandleExtAttribute(fuse_req_t req, fuse_ino_t ino, const char *name, const char *value)
883 {
884     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
885     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
886     if (inoPtr == nullptr) {
887         fuse_reply_err(req, EINVAL);
888         LOGE("inode not found");
889         return;
890     }
891     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
892     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
893     int32_t err = rdbStore->SetXAttr(inoPtr->cloudId, CLOUD_EXT_ATTR, value, name);
894     if (err != 0) {
895         LOGE("set cloud id fail %{public}d", err);
896         fuse_reply_err(req, EINVAL);
897         return;
898     }
899     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
900         NotifyOpsType::DAEMON_SETXATTR, inoPtr});
901     fuse_reply_err(req, 0);
902 }
903 
SetXattr(fuse_req_t req,fuse_ino_t ino,const char * name,const char * value,size_t size,int flags)904 void FileOperationsCloud::SetXattr(fuse_req_t req, fuse_ino_t ino, const char *name,
905                                    const char *value, size_t size, int flags)
906 {
907     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
908         LOGE("wait move error");
909         return (void) fuse_reply_err(req, EBUSY);
910     }
911     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
912     LOGD("Setxattr begin name:%{public}s", name);
913     int32_t checknum = CheckXattr(name);
914     switch (checknum) {
915         case HMDFS_PERMISSION:
916             fuse_reply_err(req, 0);
917             break;
918         case CLOUD_LOCATION:
919             HandleCloudLocation(req, ino, name, value);
920             break;
921         case CLOUD_RECYCLE:
922             HandleCloudRecycle(req, ino, name, value);
923             break;
924         case IS_FAVORITE:
925             HandleFavorite(req, ino, name, value);
926             break;
927         case HAS_THM:
928             HandleHasTHM(req, ino, name, value);
929             break;
930         default:
931             HandleExtAttribute(req, ino, name, value);
932             break;
933     }
934 }
935 
GetIsFavorite(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr)936 string GetIsFavorite(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr)
937 {
938     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
939     string favorite;
940     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
941     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
942     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
943     int res = rdbStore->GetXAttr(inoPtr->cloudId, IS_FAVORITE_XATTR, favorite);
944     if (res != 0) {
945         LOGE("local file get isFavorite fail");
946         return "null";
947     }
948     return favorite;
949 }
950 
GetFileStatus(fuse_req_t req,struct CloudDiskInode * inoPtr)951 static string GetFileStatus(fuse_req_t req, struct CloudDiskInode *inoPtr)
952 {
953     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
954     string fileStatus;
955     if (inoPtr == nullptr) {
956         LOGE("inoPtr is null");
957         return "null";
958     }
959     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
960     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
961     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
962     int res = rdbStore->GetXAttr(inoPtr->cloudId, IS_FILE_STATUS_XATTR, fileStatus);
963     if (res != 0) {
964         LOGE("local file get file_status fail");
965         return "null";
966     }
967     return fileStatus;
968 }
969 
GetLocation(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr)970 string GetLocation(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr)
971 {
972     string location;
973     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
974     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
975     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
976     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(inoPtr->parent));
977     if (parentInode == nullptr) {
978         LOGE("parent inode not found");
979         return "null";
980     }
981     CacheNode newNode = {.parentCloudId = parentInode->cloudId, .fileName = inoPtr->fileName};
982     int res = rdbStore->GetXAttr(inoPtr->cloudId, CLOUD_FILE_LOCATION, location, newNode);
983     if (res != 0) {
984         LOGE("local file get location fail");
985         return "null";
986     }
987     return location;
988 }
989 
GetTimeRecycled(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr)990 string GetTimeRecycled(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr)
991 {
992     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
993     string timeRecycled;
994     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
995     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
996     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
997     int res = rdbStore->GetXAttr(inoPtr->cloudId, CLOUD_TIME_RECYCLED, timeRecycled);
998     if (res != 0) {
999         LOGE("local file get time recycled fail");
1000         return "null";
1001     }
1002     return timeRecycled;
1003 }
1004 
GetExtAttr(fuse_req_t req,shared_ptr<CloudDiskInode> inoPtr,const char * extAttrKey)1005 string GetExtAttr(fuse_req_t req, shared_ptr<CloudDiskInode> inoPtr, const char *extAttrKey)
1006 {
1007     string extAttr;
1008     if (inoPtr == nullptr) {
1009         LOGE("get ext attr inoPtr is null");
1010         return "null";
1011     }
1012 
1013     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1014     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1015     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1016     CacheNode newNode = {};
1017     int res = rdbStore->GetXAttr(inoPtr->cloudId, CLOUD_EXT_ATTR, extAttr, newNode, extAttrKey);
1018     if (res != 0) {
1019         LOGE("get ext attr is null");
1020         return "null";
1021     }
1022     return extAttr;
1023 }
1024 
GetXattr(fuse_req_t req,fuse_ino_t ino,const char * name,size_t size)1025 void FileOperationsCloud::GetXattr(fuse_req_t req, fuse_ino_t ino, const char *name,
1026                                    size_t size)
1027 {
1028     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1029         LOGE("wait move error");
1030         return (void) fuse_reply_err(req, EBUSY);
1031     }
1032     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1033     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1034     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1035     if (inoPtr == nullptr) {
1036         fuse_reply_err(req, EINVAL);
1037         LOGE("inode not found");
1038         return;
1039     }
1040     string buf;
1041     if (CloudFileUtils::CheckIsHmdfsPermission(name)) {
1042         buf = to_string(inoPtr->layer + CLOUD_FILE_LAYER);
1043     } else if (CloudFileUtils::CheckIsCloud(name)) {
1044         buf = inoPtr->cloudId;
1045     } else if (CloudFileUtils::CheckIsFavorite(name)) {
1046         buf = GetIsFavorite(req, inoPtr);
1047     } else if (CloudFileUtils::CheckFileStatus(name)) {
1048         buf = GetFileStatus(req, inoPtr.get());
1049     } else if (CloudFileUtils::CheckIsCloudLocation(name)) {
1050         buf = GetLocation(req, inoPtr);
1051     } else if (CloudFileUtils::CheckIsTimeRecycled(name)) {
1052         buf = GetTimeRecycled(req, inoPtr);
1053     } else {
1054         buf = GetExtAttr(req, inoPtr, name);
1055     }
1056     if (buf == "null") {
1057         fuse_reply_err(req, ENODATA);
1058         return;
1059     }
1060     if (size == 0) {
1061         fuse_reply_xattr(req, buf.size());
1062         return;
1063     }
1064     if (buf.size() > size) {
1065         fuse_reply_err(req, ERANGE);
1066         return;
1067     }
1068     if (buf.size() > 0) {
1069         fuse_reply_buf(req, buf.c_str(), buf.size());
1070     } else {
1071         fuse_reply_err(req, 0);
1072     }
1073 }
1074 
MkDir(fuse_req_t req,fuse_ino_t parent,const char * name,mode_t mode)1075 void FileOperationsCloud::MkDir(fuse_req_t req, fuse_ino_t parent, const char *name, mode_t mode)
1076 {
1077     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1078         LOGE("wait move error");
1079         return (void) fuse_reply_err(req, EBUSY);
1080     }
1081     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1082     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1083     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
1084     if (parentInode == nullptr) {
1085         LOGE("parent inode not found");
1086         return (void) fuse_reply_err(req, EINVAL);
1087     }
1088     string fileName = name;
1089     bool noNeedUpload;
1090     int32_t err = 0;
1091     if (fileName == ".cloudthumbnails" && parentInode->cloudId == ROOT_CLOUD_ID) {
1092         noNeedUpload = true;
1093     } else if (parentInode->cloudId != ROOT_CLOUD_ID) {
1094         err = GetParentUpload(parentInode, data, noNeedUpload);
1095         if (err != 0) {
1096             LOGE("Failed to get parent no upload");
1097             return (void) fuse_reply_err(req, err);
1098         }
1099     }
1100     string cloudId;
1101     err = GenerateCloudId(data->userId, cloudId, parentInode->bundleName);
1102     if (err != 0) {
1103         LOGE("Failed to generate cloud id");
1104         return (void) fuse_reply_err(req, err);
1105     }
1106 
1107     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1108     shared_ptr<CloudDiskRdbStore> rdbStore = databaseManager.GetRdbStore(parentInode->bundleName,
1109                                                                          data->userId);
1110     err = rdbStore->MkDir(cloudId, parentInode->cloudId, name, noNeedUpload);
1111     if (err != 0) {
1112         LOGE("Failed to mkdir to DB err:%{public}d", err);
1113         return (void) fuse_reply_err(req, ENOSYS);
1114     }
1115 
1116     struct fuse_entry_param e;
1117     err = DoCloudLookup(req, parent, name, &e);
1118     if (err != 0) {
1119         LOGE("Failed to find dir %{private}s", GetAnonyString(name).c_str());
1120         fuse_reply_err(req, err);
1121     } else {
1122         fuse_reply_entry(req, &e);
1123     }
1124     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1125         NotifyOpsType::DAEMON_MKDIR, parentInode, parent, name});
1126 }
1127 
DoCloudUnlink(fuse_req_t req,fuse_ino_t parent,const char * name)1128 int32_t DoCloudUnlink(fuse_req_t req, fuse_ino_t parent, const char *name)
1129 {
1130     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1131     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1132     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
1133     if (parentInode == nullptr) {
1134         LOGE("parent inode not found");
1135         return ENOSYS;
1136     }
1137     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1138     shared_ptr<CloudDiskRdbStore> rdbStore = databaseManager.GetRdbStore(parentInode->bundleName, data->userId);
1139     MetaBase metaBase(name);
1140     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
1141         parentInode->bundleName, parentInode->cloudId);
1142     int32_t ret = metaFile->DoLookup(metaBase);
1143     if (ret != 0) {
1144         LOGE("lookup denty failed, name:%{public}s", GetAnonyString(name).c_str());
1145         return EINVAL;
1146     }
1147     string cloudId = metaBase.cloudId;
1148     int32_t isDirectory = S_ISDIR(metaBase.mode);
1149     int32_t position = metaBase.position;
1150     int32_t noUpload = metaBase.noUpload;
1151     ret = metaFile->DoRemove(metaBase);
1152     if (ret != 0) {
1153         LOGE("remove dentry failed, ret = %{public}d", ret);
1154         return ret;
1155     }
1156     LOGD("doUnlink, dentry file has been deleted");
1157     if (isDirectory == FILE && position != CLOUD) {
1158         string localPath = CloudFileUtils::GetLocalFilePath(cloudId, parentInode->bundleName, data->userId);
1159         LOGI("unlink %{public}s", GetAnonyString(localPath).c_str());
1160         ret = unlink(localPath.c_str());
1161         if (ret != 0 && errno == ENOENT) {
1162             std::string errMsg = "doCloudUnlink, unlink local file ret ENOENT.";
1163             CLOUD_FILE_FAULT_REPORT(CloudFileFaultInfo{parentInode->bundleName, CloudFile::FaultOperation::UNLINK,
1164                 CloudFile::FaultType::DENTRY_FILE, errno, errMsg});
1165         } else if (ret != 0) {
1166             LOGE("Failed to unlink cloudId:%{private}s, errno:%{public}d", cloudId.c_str(), errno);
1167             (void)metaFile->DoCreate(metaBase);
1168             return ret;
1169         }
1170     }
1171     function<void()> rdbUnlink = [rdbStore, cloudId, noUpload] {
1172         if (rdbStore->Unlink(cloudId, noUpload) != 0) {
1173             LOGE("Failed to unlink DB cloudId:%{private}s", cloudId.c_str());
1174         }
1175     };
1176     ffrt::thread(rdbUnlink).detach();
1177     return 0;
1178 }
1179 
RmDir(fuse_req_t req,fuse_ino_t parent,const char * name)1180 void FileOperationsCloud::RmDir(fuse_req_t req, fuse_ino_t parent, const char *name)
1181 {
1182     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1183         LOGE("wait move error");
1184         return (void) fuse_reply_err(req, EBUSY);
1185     }
1186     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1187     int32_t err = -1;
1188     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1189     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
1190     if (parentInode == nullptr) {
1191         LOGE("parent inode not found");
1192         return (void) fuse_reply_err(req, EINVAL);
1193     }
1194     auto parentMetaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
1195         parentInode->bundleName, parentInode->cloudId);
1196     MetaBase metaBase(name);
1197     err = parentMetaFile->DoLookup(metaBase);
1198     if (err != 0) {
1199         LOGE("lookup dir failed, err=%{public}d", err);
1200         return (void) fuse_reply_err(req, EINVAL);
1201     }
1202     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId,
1203         parentInode->bundleName, metaBase.cloudId);
1204     std::vector<MetaBase> bases;
1205     err = metaFile->LoadChildren(bases);
1206     if (err != 0) {
1207         LOGE("load children failed, err=%{public}d", err);
1208         return (void) fuse_reply_err(req, EINVAL);
1209     }
1210     if (!bases.empty()) {
1211         LOGE("Directory not empty");
1212         fuse_reply_err(req, ENOTEMPTY);
1213         return;
1214     }
1215     err = DoCloudUnlink(req, parent, name);
1216     if (err != 0) {
1217         fuse_reply_err(req, err);
1218         return;
1219     }
1220     MetaFileMgr::GetInstance()
1221         .Clear(static_cast<uint32_t>(data->userId), parentInode->bundleName, metaBase.cloudId);
1222     string dentryPath = metaFile->GetDentryFilePath();
1223     if (unlink(dentryPath.c_str()) != 0) {
1224         LOGE("fail to delete dentry: %{public}d", errno);
1225     }
1226     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1227         NotifyOpsType::DAEMON_RMDIR, nullptr, parent, name});
1228     return (void) fuse_reply_err(req, 0);
1229 }
1230 
Unlink(fuse_req_t req,fuse_ino_t parent,const char * name)1231 void FileOperationsCloud::Unlink(fuse_req_t req, fuse_ino_t parent, const char *name)
1232 {
1233     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1234         LOGE("wait move error");
1235         return (void) fuse_reply_err(req, EBUSY);
1236     }
1237     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1238     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1239     int32_t err = DoCloudUnlink(req, parent, name);
1240     if (err != 0) {
1241         fuse_reply_err(req, err);
1242         return;
1243     }
1244     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1245         NotifyOpsType::DAEMON_UNLINK, nullptr, parent, name});
1246     return (void) fuse_reply_err(req, 0);
1247 }
1248 
Rename(fuse_req_t req,fuse_ino_t parent,const char * name,fuse_ino_t newParent,const char * newName,unsigned int flags)1249 void FileOperationsCloud::Rename(fuse_req_t req, fuse_ino_t parent, const char *name,
1250                                  fuse_ino_t newParent, const char *newName, unsigned int flags)
1251 {
1252     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1253         LOGE("wait move error");
1254         return (void) fuse_reply_err(req, EBUSY);
1255     }
1256     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1257     if (flags) {
1258         LOGE("Fuse failed to support flag");
1259         fuse_reply_err(req, EINVAL);
1260         return;
1261     }
1262     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1263     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
1264     auto newParentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(newParent));
1265     if (!parentInode || !newParentInode) {
1266         LOGE("rename old or new parent not found");
1267         fuse_reply_err(req, EINVAL);
1268         return;
1269     }
1270 
1271     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1272     shared_ptr<CloudDiskRdbStore> rdbStore = databaseManager.GetRdbStore(parentInode->bundleName,
1273                                                                          data->userId);
1274     int32_t err = rdbStore->Rename(parentInode->cloudId, name, newParentInode->cloudId, newName);
1275     if (err != 0) {
1276         fuse_reply_err(req, err);
1277         LOGE("Failed to Rename DB name:%{private}s err:%{public}d", GetAnonyString(name).c_str(), err);
1278         return;
1279     }
1280     bool isDir = false;
1281     string key = std::to_string(parent) + name;
1282     int64_t localId = FileOperationsHelper::FindLocalId(data, key);
1283     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, localId);
1284     if (inoPtr != nullptr) {
1285         inoPtr->fileName = newName;
1286         inoPtr->parent = newParent;
1287         isDir = S_ISDIR(inoPtr->stat.st_mode);
1288     }
1289     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1290         NotifyOpsType::DAEMON_RENAME, nullptr, parent, name, newParent, newName},
1291         {FileStatus::UNKNOW, isDir});
1292     return (void) fuse_reply_err(req, 0);
1293 }
1294 
Read(fuse_req_t req,fuse_ino_t ino,size_t size,off_t offset,struct fuse_file_info * fi)1295 void FileOperationsCloud::Read(fuse_req_t req, fuse_ino_t ino, size_t size,
1296                                off_t offset, struct fuse_file_info *fi)
1297 {
1298     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1299     if (size > MAX_READ_SIZE) {
1300         fuse_reply_err(req, EINVAL);
1301         LOGE("Read size is larger than the kernel pre-read window");
1302         return;
1303     }
1304     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1305     auto filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
1306     if (filePtr == nullptr) {
1307         fuse_reply_err(req, EINVAL);
1308         LOGE("file not found");
1309         return;
1310     }
1311     if (filePtr->type == CLOUD_DISK_FILE_TYPE_LOCAL) {
1312         struct fuse_bufvec buf = FUSE_BUFVEC_INIT(size);
1313 
1314         buf.buf[0].flags = static_cast<fuse_buf_flags> (FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK);
1315         buf.buf[0].fd = filePtr->fd;
1316         buf.buf[0].pos = offset;
1317 
1318         fuse_reply_data(req, &buf, static_cast<fuse_buf_copy_flags> (0));
1319         return;
1320     }
1321 
1322     int64_t readSize;
1323     shared_ptr<char> buf = nullptr;
1324 
1325     buf.reset(new char[size], [](char* ptr) {
1326         delete[] ptr;
1327     });
1328 
1329     if (!buf) {
1330         fuse_reply_err(req, ENOMEM);
1331         LOGE("buffer is null");
1332         return;
1333     }
1334 
1335     CloudError preadError;
1336     readSize = filePtr->readSession->PRead(offset, size, buf.get(), preadError);
1337     if (!HandleCloudError(req, preadError)) {
1338         LOGD("read success, %lld bytes", static_cast<long long>(readSize));
1339         fuse_reply_buf(req, buf.get(), readSize);
1340     } else {
1341         LOGE("read fail");
1342     }
1343 }
1344 
UpdateCloudDiskInode(shared_ptr<CloudDiskRdbStore> rdbStore,shared_ptr<CloudDiskInode> inoPtr)1345 static void UpdateCloudDiskInode(shared_ptr<CloudDiskRdbStore> rdbStore, shared_ptr<CloudDiskInode> inoPtr)
1346 {
1347     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1348     CloudDiskFileInfo childInfo;
1349     int32_t err = rdbStore->GetAttr(inoPtr->cloudId, childInfo);
1350     if (err != 0) {
1351         LOGE("update file fail");
1352         return;
1353     }
1354     inoPtr->stat.st_size = childInfo.size;
1355     inoPtr->stat.st_mtime = childInfo.mtime / MILLISECOND_TO_SECONDS_TIMES;
1356 }
1357 
UpdateCloudStore(CloudDiskFuseData * data,const std::string & fileName,const std::string & parentCloudId,int fileDirty,shared_ptr<CloudDiskInode> inoPtr)1358 static void UpdateCloudStore(CloudDiskFuseData *data, const std::string &fileName, const std::string &parentCloudId,
1359     int fileDirty, shared_ptr<CloudDiskInode> inoPtr)
1360 {
1361     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1362     DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1363     auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1364     int32_t dirtyType;
1365     int res = rdbStore->GetDirtyType(inoPtr->cloudId, dirtyType);
1366     if (res != 0) {
1367         LOGE("get file status fail, err: %{public}d", res);
1368     }
1369     res = rdbStore->Write(fileName, parentCloudId, inoPtr->cloudId);
1370     if (res != 0) {
1371         LOGE("write file fail");
1372     }
1373     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1374         NotifyOpsType::DAEMON_WRITE, inoPtr}, {dirtyType, false, fileDirty});
1375     UpdateCloudDiskInode(rdbStore, inoPtr);
1376 }
1377 
UpdateCacheDentrySize(CloudDiskFuseData * data,fuse_ino_t ino)1378 static int32_t UpdateCacheDentrySize(CloudDiskFuseData *data, fuse_ino_t ino)
1379 {
1380     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1381     if (inoPtr == nullptr) {
1382         LOGE("inode not found");
1383         return ENOMEM;
1384     }
1385     string filePath = CloudFileUtils::GetLocalFilePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
1386     struct stat statInfo {};
1387     int32_t ret = stat(filePath.c_str(), &statInfo);
1388     if (ret) {
1389         LOGE("filePath %{public}s is invalid", GetAnonyString(filePath).c_str());
1390         return ret;
1391     }
1392     MetaBase metaBase(inoPtr->fileName);
1393     metaBase.mtime = static_cast<uint64_t>(CloudFileUtils::Timespec2Milliseconds(statInfo.st_mtim));
1394     metaBase.size = static_cast<uint64_t>(statInfo.st_size);
1395     auto callback = [&metaBase] (MetaBase &m) {
1396         m.size = metaBase.size;
1397         m.mtime = metaBase.mtime;
1398     };
1399     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
1400         static_cast<int64_t>(inoPtr->parent));
1401     if (parentInode == nullptr) {
1402         LOGE("fail to find parent inode");
1403         return ENOMEM;
1404     }
1405     string parentCloudId = parentInode->cloudId;
1406     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId, inoPtr->bundleName, parentCloudId);
1407     ret = metaFile->DoChildUpdate(inoPtr->fileName, callback);
1408     if (ret != 0) {
1409         LOGE("update new dentry failed, ret = %{public}d", ret);
1410         return ret;
1411     }
1412     inoPtr->stat.st_size = static_cast<decltype(inoPtr->stat.st_size)>(metaBase.size);
1413     inoPtr->stat.st_mtime =
1414         static_cast<decltype(inoPtr->stat.st_mtime)>(metaBase.mtime / MILLISECOND_TO_SECONDS_TIMES);
1415     return 0;
1416 }
1417 
WriteBuf(fuse_req_t req,fuse_ino_t ino,struct fuse_bufvec * bufv,off_t off,struct fuse_file_info * fi)1418 void FileOperationsCloud::WriteBuf(fuse_req_t req, fuse_ino_t ino, struct fuse_bufvec *bufv,
1419                                    off_t off, struct fuse_file_info *fi)
1420 {
1421     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1422     struct fuse_bufvec out_buf = FUSE_BUFVEC_INIT(fuse_buf_size(bufv));
1423     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1424     auto filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
1425     if (filePtr == nullptr) {
1426         fuse_reply_err(req, EINVAL);
1427         LOGE("file not found");
1428         return;
1429     }
1430     if (filePtr->type != CLOUD_DISK_FILE_TYPE_LOCAL) {
1431         fuse_reply_err(req, EINVAL);
1432         LOGE("write on cloud file not supported");
1433         return;
1434     }
1435     out_buf.buf[0].flags = (fuse_buf_flags)(FUSE_BUF_IS_FD | FUSE_BUF_FD_SEEK);
1436     out_buf.buf[0].fd = filePtr->fd;
1437     out_buf.buf[0].pos = off;
1438     int res = fuse_buf_copy(&out_buf, bufv, (fuse_buf_copy_flags)(0));
1439     if (res < 0) {
1440         fuse_reply_err(req, -res);
1441     } else {
1442         if (filePtr != nullptr) { filePtr->fileDirty = CLOUD_DISK_FILE_WRITE; }
1443         int32_t ret = UpdateCacheDentrySize(data, ino);
1444         if (ret != 0) {
1445             LOGE("write size in cache and dentry fail, ret = %{public}d", ret);
1446         }
1447         fuse_reply_write(req, (size_t) res);
1448     }
1449 }
1450 
UploadLocalFile(CloudDiskFuseData * data,const std::string & fileName,const std::string & parentCloudId,int fileDirty,shared_ptr<CloudDiskInode> inoPtr)1451 static void UploadLocalFile(CloudDiskFuseData *data, const std::string &fileName, const std::string &parentCloudId,
1452     int fileDirty, shared_ptr<CloudDiskInode> inoPtr)
1453 {
1454     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1455     MetaBase metaBase(fileName);
1456     auto metaFile = MetaFileMgr::GetInstance().GetCloudDiskMetaFile(data->userId, inoPtr->bundleName, parentCloudId);
1457     int32_t ret = metaFile->DoLookup(metaBase);
1458     if (ret != 0) {
1459         LOGE("local file get location from dentryfile fail, ret = %{public}d", ret);
1460     } else if (metaBase.position == LOCAL) {
1461         DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1462         auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1463         int32_t dirtyType;
1464         ret = rdbStore->GetDirtyType(inoPtr->cloudId, dirtyType);
1465         if (ret != 0) {
1466             LOGE("get file status fail, err: %{public}d", ret);
1467         }
1468         ret = rdbStore->Write(fileName, parentCloudId, inoPtr->cloudId);
1469         if (ret != 0) {
1470             LOGE("write file fail");
1471         }
1472         CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1473             NotifyOpsType::DAEMON_WRITE, inoPtr}, {dirtyType, false, fileDirty});
1474         UpdateCloudDiskInode(rdbStore, inoPtr);
1475     }
1476 }
1477 
Release(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)1478 void FileOperationsCloud::Release(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
1479 {
1480     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1481     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1482     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1483     if (inoPtr == nullptr) {
1484         LOGE("inode not found");
1485         fuse_reply_err(req, EINVAL);
1486         return;
1487     }
1488     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
1489         static_cast<int64_t>(inoPtr->parent));
1490     if (parentInode == nullptr) {
1491         fuse_reply_err(req, EINVAL);
1492         LOGE("fail to find parent inode");
1493         return;
1494     }
1495     string parentCloudId = parentInode->cloudId;
1496     shared_ptr<CloudDiskFile> filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
1497     if (filePtr == nullptr) {
1498         fuse_reply_err(req, EINVAL);
1499         LOGE("file not found");
1500         return;
1501     }
1502     filePtr->refCount--;
1503     if (filePtr->refCount == 0) {
1504         if (filePtr->type == CLOUD_DISK_FILE_TYPE_LOCAL) {
1505             close(filePtr->fd);
1506             if (filePtr->fileDirty != CLOUD_DISK_FILE_UNKNOWN) {
1507                 UpdateCloudStore(data, inoPtr->fileName, parentCloudId, filePtr->fileDirty, inoPtr);
1508             } else if (filePtr->isWriteOpen) {
1509                 UploadLocalFile(data, inoPtr->fileName, parentCloudId, filePtr->fileDirty, inoPtr);
1510             }
1511         } else if (filePtr->type == CLOUD_DISK_FILE_TYPE_CLOUD &&
1512             filePtr->readSession != nullptr) {
1513             bool res = filePtr->readSession->Close(false);
1514             if (!res) {
1515                 LOGE("close error");
1516                 fuse_reply_err(req, ENOSYS);
1517                 return;
1518             }
1519             filePtr->readSession = nullptr;
1520             LOGD("readSession released");
1521         }
1522         FileOperationsHelper::PutCloudDiskFile(data, filePtr, fi->fh);
1523     }
1524     fuse_reply_err(req, 0);
1525 }
1526 
SetAttr(fuse_req_t req,fuse_ino_t ino,struct stat * attr,int valid,struct fuse_file_info * fi)1527 void FileOperationsCloud::SetAttr(fuse_req_t req, fuse_ino_t ino, struct stat *attr,
1528                                   int valid, struct fuse_file_info *fi)
1529 {
1530     if (WaitParameter("persist.kernel.move.finish", "true", MOVE_FILE_TIME_DAEMON) != 0) {
1531         LOGE("wait move error");
1532         return (void) fuse_reply_err(req, EBUSY);
1533     }
1534     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1535     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1536     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1537     if (inoPtr == nullptr) {
1538         LOGE("get an invalid inode!");
1539         fuse_reply_err(req, EINVAL);
1540         return;
1541     }
1542     auto parentInode = FileOperationsHelper::FindCloudDiskInode(data,
1543         static_cast<int64_t>(inoPtr->parent));
1544     if (parentInode == nullptr) {
1545         LOGE("parent inode not found");
1546         fuse_reply_err(req, EINVAL);
1547         return;
1548     }
1549     if (static_cast<unsigned int>(valid) & FUSE_SET_ATTR_SIZE) {
1550         DatabaseManager &databaseManager = DatabaseManager::GetInstance();
1551         auto rdbStore = databaseManager.GetRdbStore(inoPtr->bundleName, data->userId);
1552         int32_t res = rdbStore->SetAttr(inoPtr->fileName, parentInode->cloudId, inoPtr->cloudId, attr->st_size);
1553         if (res != 0) {
1554             LOGE("update rdb size failed, res: %{public}d", res);
1555             fuse_reply_err(req, ENOSYS);
1556             return;
1557         }
1558         if (fi) {
1559             auto filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
1560             if (filePtr == nullptr) {
1561                 LOGE("file not found");
1562                 return (void) fuse_reply_err(req, EINVAL);
1563             }
1564             res = ftruncate(filePtr->fd, attr->st_size);
1565         } else {
1566             string path = CloudFileUtils::GetLocalFilePath(inoPtr->cloudId, inoPtr->bundleName, data->userId);
1567             res = truncate(path.c_str(), attr->st_size);
1568         }
1569         if (res == -1) {
1570             LOGE("truncate failed, err: %{public}d", errno);
1571             res = rdbStore->SetAttr(inoPtr->fileName, parentInode->cloudId, inoPtr->cloudId,
1572                 inoPtr->stat.st_size);
1573             if (res != 0) {
1574                 LOGE("update rdb size failed, res: %{public}d", res);
1575                 fuse_reply_err(req, ENOSYS);
1576             } else {
1577                 fuse_reply_err(req, errno);
1578             }
1579             return;
1580         }
1581         UpdateCloudDiskInode(rdbStore, inoPtr);
1582     }
1583     CloudDiskNotify::GetInstance().TryNotify({data, FileOperationsHelper::FindCloudDiskInode,
1584         NotifyOpsType::DAEMON_SETATTR, inoPtr});
1585     fuse_reply_attr(req, &inoPtr->stat, 0);
1586 }
1587 
Lseek(fuse_req_t req,fuse_ino_t ino,off_t off,int whence,struct fuse_file_info * fi)1588 void FileOperationsCloud::Lseek(fuse_req_t req, fuse_ino_t ino, off_t off, int whence,
1589                                 struct fuse_file_info *fi)
1590 {
1591     HITRACE_METER_NAME(HITRACE_TAG_FILEMANAGEMENT, __PRETTY_FUNCTION__);
1592     auto data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
1593     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
1594     if (inoPtr == nullptr) {
1595         LOGE("get an invalid inode!");
1596         fuse_reply_err(req, EINVAL);
1597         return;
1598     }
1599     shared_ptr<CloudDiskFile> filePtr = FileOperationsHelper::FindCloudDiskFile(data, fi->fh);
1600     if (filePtr == nullptr) {
1601         fuse_reply_err(req, EINVAL);
1602         LOGE("file not found");
1603         return;
1604     }
1605     if (filePtr->type != CLOUD_DISK_FILE_TYPE_LOCAL) {
1606         fuse_reply_err(req, ENOSYS);
1607         LOGE("lseek on cloud file not supported");
1608         return;
1609     }
1610     off_t res = lseek(filePtr->fd, off, whence);
1611     if (res != -1)
1612         fuse_reply_lseek(req, res);
1613     else
1614         fuse_reply_err(req, errno);
1615 }
1616 } // namespace CloudDisk
1617 } // namespace FileManagement
1618 } // namespace OHOS
1619