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