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