• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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_local.h"
16 
17 #include <cerrno>
18 #include <dirent.h>
19 
20 #include "cloud_file_fault_event.h"
21 #include "file_operations_cloud.h"
22 #include "file_operations_helper.h"
23 #include "utils_log.h"
24 #include "xcollie_helper.h"
25 
26 namespace OHOS {
27 namespace FileManagement {
28 namespace CloudDisk {
29 using namespace std;
30 static const int32_t BUNDLE_NAME_OFFSET = 1000000000;
31 static const int32_t STAT_MODE_DIR = 0771;
32 static const float LOOKUP_TIMEOUT = 60.0;
33 #ifdef HICOLLIE_ENABLE
34 static const unsigned int LOOKUP_TIMEOUT_S = 1;
35 static const unsigned int GETATTR_TIMEOUT_S = 1;
36 #endif
37 
DoLocalLookup(fuse_req_t req,fuse_ino_t parent,const char * name,struct fuse_entry_param * e)38 static int32_t DoLocalLookup(fuse_req_t req, fuse_ino_t parent, const char *name,
39                              struct fuse_entry_param *e)
40 {
41     bool createFlag = false;
42     struct CloudDiskFuseData *data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
43     string path = FileOperationsHelper::GetCloudDiskLocalPath(data->userId, name);
44     std::unique_lock<std::shared_mutex> cWLock(data->cacheLock, std::defer_lock);
45     string key = std::to_string(parent) + name;
46     int64_t localId = FileOperationsHelper::FindLocalId(data, key);
47     auto child = FileOperationsHelper::FindCloudDiskInode(data, localId);
48     if (child == nullptr) {
49         child = make_shared<CloudDiskInode>();
50         createFlag = true;
51         LOGD("new child %{public}s", name);
52     }
53     std::unique_lock<std::shared_mutex> lWLock(data->localIdLock, std::defer_lock);
54     child->refCount++;
55     if (createFlag) {
56         if (stat(path.c_str(), &child->stat) != 0) {
57             CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{child->bundleName, CloudFile::FaultOperation::LOOKUP,
58                 CloudFile::FaultType::INODE_FILE, errno, "lookup " + GetAnonyString(path) + " error, err: " +
59                 std::to_string(errno)});
60             return errno;
61         }
62         child->stat.st_mode |= STAT_MODE_DIR;
63         child->parent = parent;
64         child->path = path;
65         auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
66         child->layer = FileOperationsHelper::GetNextLayer(parentInode, parent);
67         localId = FileOperationsHelper::GetFixedLayerRootId(child->layer);
68         if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
69             std::lock_guard<std::shared_mutex> bWLock(data->bundleNameIdLock);
70             data->bundleNameId++;
71             localId = data->bundleNameId + BUNDLE_NAME_OFFSET;
72         }
73         child->stat.st_ino = static_cast<uint64_t>(localId);
74         child->ops = make_shared<FileOperationsLocal>();
75         cWLock.lock();
76         data->inodeCache[localId] = child;
77         cWLock.unlock();
78         lWLock.lock();
79         data->localIdCache[key] = localId;
80         lWLock.unlock();
81     }
82     if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
83         child->bundleName = name;
84         child->ops = make_shared<FileOperationsCloud>();
85     }
86     e->ino = static_cast<fuse_ino_t>(localId);
87     FileOperationsHelper::GetInodeAttr(child, &e->attr);
88     return 0;
89 }
90 
Lookup(fuse_req_t req,fuse_ino_t parent,const char * name)91 void FileOperationsLocal::Lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
92 {
93     struct fuse_entry_param e;
94     int32_t err;
95     e.attr_timeout = LOOKUP_TIMEOUT;
96     e.entry_timeout = LOOKUP_TIMEOUT;
97 #ifdef HICOLLIE_ENABLE
98     auto xcollieId = XCollieHelper::SetTimer("CloudDisk_Lookup", LOOKUP_TIMEOUT_S, nullptr, nullptr, false);
99 #endif
100     err = DoLocalLookup(req, parent, name, &e);
101     if (err) {
102         fuse_reply_err(req, err);
103     } else {
104         fuse_reply_entry(req, &e);
105     }
106 #ifdef HICOLLIE_ENABLE
107     XCollieHelper::CancelTimer(xcollieId);
108 #endif
109 }
110 
GetAttr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)111 void FileOperationsLocal::GetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
112 {
113 #ifdef HICOLLIE_ENABLE
114     auto xcollieId = XCollieHelper::SetTimer("CloudDisk_GetAttr", GETATTR_TIMEOUT_S, nullptr, nullptr, false);
115 #endif
116     struct CloudDiskFuseData *data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
117     if (ino == FUSE_ROOT_ID) {
118         string path = FileOperationsHelper::GetCloudDiskRootPath(data->userId);
119 
120         struct stat statBuf;
121         int err = stat(path.c_str(), &statBuf);
122         if (err != 0) {
123             CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETATTR,
124                 CloudFile::FaultType::FILE, errno, "lookup " + GetAnonyString(path) + " error, err: " +
125                 std::to_string(errno)});
126             fuse_reply_err(req, errno);
127 #ifdef HICOLLIE_ENABLE
128             XCollieHelper::CancelTimer(xcollieId);
129 #endif
130             return;
131         }
132         fuse_reply_attr(req, &statBuf, 0);
133 #ifdef HICOLLIE_ENABLE
134         XCollieHelper::CancelTimer(xcollieId);
135 #endif
136         return;
137     }
138     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
139     if (inoPtr == nullptr) {
140         CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::GETATTR,
141             CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
142         fuse_reply_err(req, EINVAL);
143 #ifdef HICOLLIE_ENABLE
144         XCollieHelper::CancelTimer(xcollieId);
145 #endif
146         return;
147     }
148     fuse_reply_attr(req, &inoPtr->stat, 0);
149 #ifdef HICOLLIE_ENABLE
150     XCollieHelper::CancelTimer(xcollieId);
151 #endif
152 }
153 
ReadDir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)154 void FileOperationsLocal::ReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
155                                   struct fuse_file_info *fi)
156 {
157     (void) fi;
158     string path;
159     struct CloudDiskFuseData *data =
160         reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
161     if (ino == FUSE_ROOT_ID) {
162         path = FileOperationsHelper::GetCloudDiskRootPath(data->userId);
163     } else {
164         auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
165         if (inoPtr == nullptr) {
166             CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READDIR,
167                 CloudFile::FaultType::INODE_FILE, EINVAL, "inode not found"});
168             fuse_reply_err(req, EINVAL);
169             return;
170         }
171         path = inoPtr->path;
172     }
173     DIR* dir = opendir(path.c_str());
174     if (dir == NULL) {
175         CLOUD_FILE_FAULT_REPORT(CloudFile::CloudFileFaultInfo{"", CloudFile::FaultOperation::READDIR,
176             CloudFile::FaultType::FILE, errno, "opendir error " + std::to_string(errno) + ", path: " +
177             GetAnonyString(path)});
178         return;
179     }
180 
181     struct dirent *entry;
182     string entryData;
183     size_t len = 0;
184     while ((entry = readdir(dir)) != NULL) {
185         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
186             continue;
187         }
188 
189         string childPath = FileOperationsHelper::GetCloudDiskLocalPath(data->userId,
190             entry->d_name);
191         int64_t key = FileOperationsHelper::FindLocalId(data, std::to_string(ino) +
192             entry->d_name);
193         auto childPtr = FileOperationsHelper::FindCloudDiskInode(data, key);
194         if (childPtr == nullptr) {
195             childPtr = FileOperationsHelper::GenerateCloudDiskInode(data, ino,
196                 entry->d_name, childPath.c_str());
197         }
198         if (childPtr == nullptr) {
199             continue;
200         }
201         FileOperationsHelper::AddDirEntry(req, entryData, len, entry->d_name, childPtr);
202     }
203     FileOperationsHelper::FuseReplyLimited(req, entryData.c_str(), len, off, size);
204     closedir(dir);
205     return;
206 }
207 } // namespace CloudDisk
208 } // namespace FileManagement
209 } // namespace OHOS
210