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