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