1 /*
2 * Copyright (c) 2023 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_local.h"
16
17 #include <cerrno>
18 #include <dirent.h>
19
20 #include "file_operations_cloud.h"
21 #include "file_operations_helper.h"
22 #include "utils_log.h"
23
24 namespace OHOS {
25 namespace FileManagement {
26 namespace CloudDisk {
27 using namespace std;
28
DoLocalLookup(fuse_req_t req,fuse_ino_t parent,const char * name,struct fuse_entry_param * e)29 static int32_t DoLocalLookup(fuse_req_t req, fuse_ino_t parent, const char *name,
30 struct fuse_entry_param *e)
31 {
32 int32_t err = 0;
33 bool createFlag = false;
34 shared_ptr<CloudDiskInode> child;
35 struct CloudDiskFuseData *data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
36 string path = FileOperationsHelper::GetCloudDiskLocalPath(data->userId, name);
37 std::unique_lock<std::shared_mutex> wLock(data->cacheLock, std::defer_lock);
38
39 child = FileOperationsHelper::FindCloudDiskInode(data, path);
40 if (child == nullptr) {
41 child = make_shared<CloudDiskInode>();
42 createFlag = true;
43 LOGD("new child %{public}s", name);
44 }
45
46 err = stat(path.c_str(), &child->stat);
47 if (err != 0) {
48 LOGE("lookup %{public}s error, err: %{public}d", path.c_str(), errno);
49 return errno;
50 }
51
52 child->refCount++;
53 if (createFlag) {
54 child->parent = parent;
55 child->path = path;
56 child->layer = FileOperationsHelper::GetNextLayer(parent);
57 child->stat.st_ino = reinterpret_cast<fuse_ino_t>(child.get());
58 child->ops = make_shared<FileOperationsLocal>();
59 wLock.lock();
60 data->inodeCache[path] = child;
61 wLock.unlock();
62 }
63 if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
64 child->bundleName = name;
65 child->ops = make_shared<FileOperationsCloud>();
66 }
67 e->ino = reinterpret_cast<fuse_ino_t>(child.get());
68 FileOperationsHelper::GetInodeAttr(child, &e->attr);
69 return 0;
70 }
71
Lookup(fuse_req_t req,fuse_ino_t parent,const char * name)72 void FileOperationsLocal::Lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
73 {
74 struct fuse_entry_param e;
75 int32_t err;
76
77 err = DoLocalLookup(req, parent, name, &e);
78 if (err) {
79 fuse_reply_err(req, err);
80 } else {
81 fuse_reply_entry(req, &e);
82 }
83 }
84
GetAttr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)85 void FileOperationsLocal::GetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
86 {
87 if (ino == FUSE_ROOT_ID) {
88 struct CloudDiskFuseData *data =
89 reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
90 string path = FileOperationsHelper::GetCloudDiskRootPath(data->userId);
91
92 struct stat statBuf;
93 int err = stat(path.c_str(), &statBuf);
94 if (err != 0) {
95 LOGE("lookup %{public}s error, err: %{public}d", path.c_str(), err);
96 fuse_reply_err(req, err);
97 return;
98 }
99 fuse_reply_attr(req, &statBuf, 0);
100 return;
101 }
102 struct CloudDiskInode *inoPtr = reinterpret_cast<struct CloudDiskInode *>(ino);
103 fuse_reply_attr(req, &inoPtr->stat, 0);
104 }
105
Forget(fuse_req_t req,fuse_ino_t ino,uint64_t nLookup)106 void FileOperationsLocal::Forget(fuse_req_t req, fuse_ino_t ino, uint64_t nLookup)
107 {
108 struct CloudDiskFuseData *data =
109 reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
110 string key = FileOperationsHelper::GetCloudDiskRootPath(data->userId);
111 if (ino != FUSE_ROOT_ID) {
112 struct CloudDiskInode *inoPtr = reinterpret_cast<struct CloudDiskInode *>(ino);
113 key = inoPtr->path;
114 }
115 shared_ptr<CloudDiskInode> node = FileOperationsHelper::FindCloudDiskInode(data, key);
116 FileOperationsHelper::PutCloudDiskInode(data, node, nLookup, key);
117 fuse_reply_none(req);
118 }
119
ReadDir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)120 void FileOperationsLocal::ReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
121 struct fuse_file_info *fi)
122 {
123 (void) fi;
124 string path;
125 struct CloudDiskInode *inoPtr = reinterpret_cast<struct CloudDiskInode *>(ino);
126 struct CloudDiskFuseData *data =
127 reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
128 shared_ptr<CloudDiskInode> child;
129 if (ino == FUSE_ROOT_ID) {
130 path = FileOperationsHelper::GetCloudDiskRootPath(data->userId);
131 } else {
132 path = inoPtr->path;
133 }
134 DIR* dir = opendir(path.c_str());
135 if (dir == NULL) {
136 LOGE("opendir error %{public}d, path:%{public}s", errno, path.c_str());
137 return;
138 }
139
140 struct dirent *entry;
141 string entryData;
142 size_t len = 0;
143 while ((entry = readdir(dir)) != NULL) {
144 if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
145 continue;
146 }
147
148 string childPath = FileOperationsHelper::GetCloudDiskLocalPath(data->userId, entry->d_name);
149 shared_ptr<CloudDiskInode> childPtr = FileOperationsHelper::FindCloudDiskInode(
150 data, childPath.c_str());
151 if (childPtr == nullptr) {
152 childPtr = FileOperationsHelper::GenerateCloudDiskInode(data, inoPtr,
153 entry->d_name, childPath.c_str());
154 }
155 if (childPtr == nullptr) {
156 continue;
157 }
158 FileOperationsHelper::AddDirEntry(req, entryData, len, entry->d_name, childPtr);
159 }
160 FileOperationsHelper::FuseReplyLimited(req, entryData.c_str(), len, off, size);
161 closedir(dir);
162 return;
163 }
164 } // namespace CloudDisk
165 } // namespace FileManagement
166 } // namespace OHOS
167