1 /*
2 * Copyright (c) 2023-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_helper.h"
16
17 #include <cinttypes>
18 #include <unistd.h>
19
20 #include "cloud_file_fault_event.h"
21 #include "file_operations_cloud.h"
22 #include "file_operations_local.h"
23 #include "securec.h"
24 #include "utils_log.h"
25
26 namespace OHOS {
27 namespace FileManagement {
28 namespace CloudDisk {
29 using namespace std;
30 namespace {
31 static const string LOCAL_PATH_DATA_SERVICE_EL2 = "/data/service/el2/";
32 static const string LOCAL_PATH_HMDFS_CLOUD_DATA = "/hmdfs/cloud/data/";
33 static const string LOCAL_PATH_HMDFS_CLOUD = "/hmdfs/cloud/";
34 static const int32_t BUNDLE_NAME_OFFSET = 1000000000;
35 static const int32_t STAT_MODE_DIR = 0771;
36 }
37
GetCloudDiskRootPath(int32_t userId)38 string FileOperationsHelper::GetCloudDiskRootPath(int32_t userId)
39 {
40 return LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) + LOCAL_PATH_HMDFS_CLOUD;
41 }
42
GetCloudDiskLocalPath(int32_t userId,string fileName)43 string FileOperationsHelper::GetCloudDiskLocalPath(int32_t userId, string fileName)
44 {
45 if (fileName == "data") {
46 return LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) +
47 LOCAL_PATH_HMDFS_CLOUD_DATA;
48 } else if (fileName == "/") {
49 return GetCloudDiskRootPath(userId);
50 } else {
51 return LOCAL_PATH_DATA_SERVICE_EL2 + to_string(userId) +
52 LOCAL_PATH_HMDFS_CLOUD_DATA + fileName;
53 }
54 }
55
GetInodeAttr(shared_ptr<CloudDiskInode> ino,struct stat * statBuf)56 void FileOperationsHelper::GetInodeAttr(shared_ptr<CloudDiskInode> ino, struct stat *statBuf)
57 {
58 statBuf->st_ino = ino->stat.st_ino;
59 statBuf->st_uid = ino->stat.st_uid;
60 statBuf->st_gid = ino->stat.st_gid;
61 statBuf->st_mtime = ino->stat.st_mtime;
62 statBuf->st_ctime = ino->stat.st_ctime;
63 statBuf->st_atime = ino->stat.st_atime;
64 statBuf->st_mode = ino->stat.st_mode;
65 statBuf->st_nlink = ino->stat.st_nlink;
66 if (statBuf->st_mode & S_IFREG) {
67 statBuf->st_size = ino->stat.st_size;
68 }
69 }
70
GetNextLayer(std::shared_ptr<CloudDiskInode> inoPtr,fuse_ino_t ino)71 int32_t FileOperationsHelper::GetNextLayer(std::shared_ptr<CloudDiskInode> inoPtr, fuse_ino_t ino)
72 {
73 if (ino == FUSE_ROOT_ID) {
74 return CLOUD_DISK_INODE_ZERO_LAYER;
75 }
76 if (inoPtr->layer >= CLOUD_DISK_INODE_OTHER_LAYER) {
77 return CLOUD_DISK_INODE_OTHER_LAYER;
78 } else {
79 return inoPtr->layer + 1;
80 }
81 }
82
GetFixedLayerRootId(int32_t layer)83 int32_t FileOperationsHelper::GetFixedLayerRootId(int32_t layer)
84 {
85 if (layer == CLOUD_DISK_INODE_ZERO_LAYER) {
86 return CLOUD_DISK_INODE_ZERO_LAYER_LOCALID;
87 } else if (layer == CLOUD_DISK_INODE_FIRST_LAYER) {
88 return CLOUD_DISK_INODE_FIRST_LAYER_LOCALID;
89 }
90 return CLOUD_DISK_INODE_LAYER_LOCALID_UNKNOWN;
91 }
92
FindCloudDiskInode(struct CloudDiskFuseData * data,int64_t key)93 shared_ptr<CloudDiskInode> FileOperationsHelper::FindCloudDiskInode(struct CloudDiskFuseData *data,
94 int64_t key)
95 {
96 shared_ptr<CloudDiskInode> ret;
97 shared_lock<shared_mutex> rLock(data->cacheLock, std::defer_lock);
98 rLock.lock();
99 auto it = data->inodeCache.find(key);
100 if (it != data->inodeCache.end()) {
101 ret = it->second;
102 } else {
103 ret = nullptr;
104 }
105 rLock.unlock();
106 return ret;
107 }
108
FindCloudDiskFile(struct CloudDiskFuseData * data,int64_t key)109 shared_ptr<CloudDiskFile> FileOperationsHelper::FindCloudDiskFile(struct CloudDiskFuseData *data,
110 int64_t key)
111 {
112 shared_ptr<CloudDiskFile> ret;
113 shared_lock<shared_mutex> rLock(data->fileLock, std::defer_lock);
114 rLock.lock();
115 auto it = data->fileCache.find(key);
116 if (it != data->fileCache.end()) {
117 ret = it->second;
118 } else {
119 ret = nullptr;
120 }
121 rLock.unlock();
122 return ret;
123 }
124
FindLocalId(struct CloudDiskFuseData * data,const std::string & key)125 int64_t FileOperationsHelper::FindLocalId(struct CloudDiskFuseData *data, const std::string &key)
126 {
127 int64_t ret = -1;
128 shared_lock<shared_mutex> rLock(data->localIdLock, std::defer_lock);
129 rLock.lock();
130 auto it = data->localIdCache.find(key);
131 if (it != data->localIdCache.end()) {
132 ret = it->second;
133 } else {
134 ret = -1;
135 }
136 rLock.unlock();
137 return ret;
138 }
139
AddDirEntry(fuse_req_t req,std::string & buf,size_t & size,const char * name,std::shared_ptr<CloudDiskInode> ino)140 void FileOperationsHelper::AddDirEntry(fuse_req_t req, std::string &buf, size_t &size, const char *name,
141 std::shared_ptr<CloudDiskInode> ino)
142 {
143 size_t oldSize = size;
144 size += fuse_add_direntry(req, NULL, 0, name, NULL, 0);
145 buf.resize(size);
146 fuse_add_direntry(req, &buf[oldSize], size - oldSize, name, &ino->stat, size);
147 }
148
FuseReplyLimited(fuse_req_t req,const char * buf,size_t bufSize,off_t off,size_t maxSize)149 void FileOperationsHelper::FuseReplyLimited(fuse_req_t req, const char *buf, size_t bufSize,
150 off_t off, size_t maxSize)
151 {
152 if (off < static_cast<off_t>(bufSize)) {
153 size_t size = (bufSize - off) < maxSize ? (bufSize - off) : maxSize;
154 fuse_reply_buf(req, buf + off, size);
155 } else {
156 fuse_reply_buf(req, NULL, 0);
157 }
158 }
159
GenerateCloudDiskInode(struct CloudDiskFuseData * data,fuse_ino_t parent,const string & fileName,const string & path)160 shared_ptr<CloudDiskInode> FileOperationsHelper::GenerateCloudDiskInode(struct CloudDiskFuseData *data,
161 fuse_ino_t parent,
162 const string &fileName,
163 const string &path)
164 {
165 std::unique_lock<std::shared_mutex> cWLock(data->cacheLock, std::defer_lock);
166 std::unique_lock<std::shared_mutex> lWLock(data->localIdLock, std::defer_lock);
167 shared_ptr<CloudDiskInode> child = make_shared<CloudDiskInode>();
168 int32_t err = stat(path.c_str(), &child->stat);
169 if (err != 0) {
170 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{child->bundleName, CloudFile::FaultOperation::READDIR,
171 CloudFile::FaultType::INODE_FILE, errno, "GenerateCloudDiskInode " + GetAnonyString(path) + " error" +
172 "err: " + std::to_string(errno)});
173 return nullptr;
174 }
175 child->stat.st_mode |= STAT_MODE_DIR;
176 auto parentInode = FindCloudDiskInode(data, parent);
177 if (parentInode == nullptr) {
178 CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{child->bundleName, CloudFile::FaultOperation::READDIR,
179 CloudFile::FaultType::INODE_FILE, EINVAL, "parent inode not found"});
180 return nullptr;
181 }
182 child->refCount++;
183 child->parent = parent;
184 child->path = path;
185 child->layer = GetNextLayer(parentInode, parent);
186 int64_t localId = GetFixedLayerRootId(child->layer);
187 if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
188 std::lock_guard<std::shared_mutex> bWLock(data->bundleNameIdLock);
189 data->bundleNameId++;
190 localId = data->bundleNameId + BUNDLE_NAME_OFFSET;
191 }
192 child->stat.st_ino = static_cast<uint64_t>(localId);
193 child->ops = make_shared<FileOperationsLocal>();
194 cWLock.lock();
195 data->inodeCache[localId] = child;
196 cWLock.unlock();
197 lWLock.lock();
198 data->localIdCache[path] = localId;
199 lWLock.unlock();
200 if (child->layer == CLOUD_DISK_INODE_FIRST_LAYER) {
201 child->bundleName = fileName;
202 child->ops = make_shared<FileOperationsCloud>();
203 }
204 return child;
205 }
206
PutCloudDiskInode(struct CloudDiskFuseData * data,shared_ptr<CloudDiskInode> inoPtr,uint64_t num,int64_t key)207 void FileOperationsHelper::PutCloudDiskInode(struct CloudDiskFuseData *data,
208 shared_ptr<CloudDiskInode> inoPtr, uint64_t num, int64_t key)
209 {
210 std::unique_lock<std::shared_mutex> wLock(data->cacheLock, std::defer_lock);
211 if (inoPtr == nullptr) {
212 LOGD("Get an invalid inode!");
213 return;
214 }
215 inoPtr->refCount -= num;
216 if (inoPtr->refCount == 0) {
217 LOGD("node released: %{public}" PRId64 "", key);
218 wLock.lock();
219 data->inodeCache.erase(key);
220 wLock.unlock();
221 }
222 }
223
PutCloudDiskFile(struct CloudDiskFuseData * data,shared_ptr<CloudDiskFile> filePtr,int64_t key)224 void FileOperationsHelper::PutCloudDiskFile(struct CloudDiskFuseData *data,
225 shared_ptr<CloudDiskFile> filePtr, int64_t key)
226 {
227 std::unique_lock<std::shared_mutex> wLock(data->fileLock, std::defer_lock);
228 if (filePtr == nullptr) {
229 LOGD("Get an invalid file!");
230 return;
231 }
232 if (filePtr->refCount == 0) {
233 LOGD("file released: %{public}" PRId64 "", key);
234 wLock.lock();
235 data->fileCache.erase(key);
236 wLock.unlock();
237 }
238 }
239
PutLocalId(struct CloudDiskFuseData * data,std::shared_ptr<CloudDiskInode> inoPtr,uint64_t num,const std::string & key)240 void FileOperationsHelper::PutLocalId(struct CloudDiskFuseData *data,
241 std::shared_ptr<CloudDiskInode> inoPtr,
242 uint64_t num, const std::string &key)
243 {
244 std::unique_lock<std::shared_mutex> wLock(data->localIdLock, std::defer_lock);
245 if (inoPtr == nullptr) {
246 LOGD("Get an invalid inode!");
247 return;
248 }
249 inoPtr->refCount -= num;
250 if (inoPtr->refCount == 0) {
251 LOGD("node released: %{public}s", key.c_str());
252 wLock.lock();
253 data->localIdCache.erase(key);
254 wLock.unlock();
255 }
256 }
257 } // namespace CloudDisk
258 } // namespace FileManagement
259 } // namespace OHOS
260