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