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 "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 static const int32_t BUNDLE_NAME_OFFSET = 1000000000;
29 static const int32_t STAT_MODE_DIR = 0771;
30 static const float LOOKUP_TIMEOUT = 60.0;
31 
DoLocalLookup(fuse_req_t req,fuse_ino_t parent,const char * name,struct fuse_entry_param * e)32 static int32_t DoLocalLookup(fuse_req_t req, fuse_ino_t parent, const char *name,
33                              struct fuse_entry_param *e)
34 {
35     int32_t err = 0;
36     bool createFlag = false;
37     struct CloudDiskFuseData *data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
38     string path = FileOperationsHelper::GetCloudDiskLocalPath(data->userId, name);
39     std::unique_lock<std::shared_mutex> cWLock(data->cacheLock, std::defer_lock);
40     string key = std::to_string(parent) + name;
41     int64_t localId = FileOperationsHelper::FindLocalId(data, key);
42     auto child = FileOperationsHelper::FindCloudDiskInode(data, localId);
43     if (child == nullptr) {
44         child = make_shared<CloudDiskInode>();
45         createFlag = true;
46         LOGD("new child %{public}s", name);
47     }
48     std::unique_lock<std::shared_mutex> lWLock(data->localIdLock, std::defer_lock);
49     child->refCount++;
50     if (createFlag) {
51         err = stat(path.c_str(), &child->stat);
52         if (err != 0) {
53             LOGE("lookup %{public}s error, err: %{public}d", GetAnonyString(path).c_str(), errno);
54             return errno;
55         }
56         child->stat.st_mode |= STAT_MODE_DIR;
57         child->parent = parent;
58         child->path = path;
59         auto parentInode = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(parent));
60         child->layer = FileOperationsHelper::GetNextLayer(parentInode, parent);
61         localId = FileOperationsHelper::GetFixedLayerRootId(child->layer);
62         if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
63             std::lock_guard<std::shared_mutex> bWLock(data->bundleNameIdLock);
64             data->bundleNameId++;
65             localId = data->bundleNameId + BUNDLE_NAME_OFFSET;
66         }
67         child->stat.st_ino = static_cast<uint64_t>(localId);
68         child->ops = make_shared<FileOperationsLocal>();
69         cWLock.lock();
70         data->inodeCache[localId] = child;
71         cWLock.unlock();
72         lWLock.lock();
73         data->localIdCache[key] = localId;
74         lWLock.unlock();
75     }
76     if (child->layer >= CLOUD_DISK_INODE_FIRST_LAYER) {
77         child->bundleName = name;
78         child->ops = make_shared<FileOperationsCloud>();
79     }
80     e->ino = static_cast<fuse_ino_t>(localId);
81     FileOperationsHelper::GetInodeAttr(child, &e->attr);
82     return 0;
83 }
84 
Lookup(fuse_req_t req,fuse_ino_t parent,const char * name)85 void FileOperationsLocal::Lookup(fuse_req_t req, fuse_ino_t parent, const char *name)
86 {
87     struct fuse_entry_param e;
88     int32_t err;
89     e.attr_timeout = LOOKUP_TIMEOUT;
90     e.entry_timeout = LOOKUP_TIMEOUT;
91     err = DoLocalLookup(req, parent, name, &e);
92     if (err) {
93         fuse_reply_err(req, err);
94     } else {
95         fuse_reply_entry(req, &e);
96     }
97 }
98 
GetAttr(fuse_req_t req,fuse_ino_t ino,struct fuse_file_info * fi)99 void FileOperationsLocal::GetAttr(fuse_req_t req, fuse_ino_t ino, struct fuse_file_info *fi)
100 {
101     struct CloudDiskFuseData *data = reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
102     if (ino == FUSE_ROOT_ID) {
103         string path = FileOperationsHelper::GetCloudDiskRootPath(data->userId);
104 
105         struct stat statBuf;
106         int err = stat(path.c_str(), &statBuf);
107         if (err != 0) {
108             LOGE("lookup %{public}s error, err: %{public}d", GetAnonyString(path).c_str(), err);
109             fuse_reply_err(req, err);
110             return;
111         }
112         fuse_reply_attr(req, &statBuf, 0);
113         return;
114     }
115     auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
116     if (inoPtr == nullptr) {
117         fuse_reply_err(req, EINVAL);
118         LOGE("inode not found");
119         return;
120     }
121     fuse_reply_attr(req, &inoPtr->stat, 0);
122 }
123 
ReadDir(fuse_req_t req,fuse_ino_t ino,size_t size,off_t off,struct fuse_file_info * fi)124 void FileOperationsLocal::ReadDir(fuse_req_t req, fuse_ino_t ino, size_t size, off_t off,
125                                   struct fuse_file_info *fi)
126 {
127     (void) fi;
128     string path;
129     struct CloudDiskFuseData *data =
130         reinterpret_cast<struct CloudDiskFuseData *>(fuse_req_userdata(req));
131     if (ino == FUSE_ROOT_ID) {
132         path = FileOperationsHelper::GetCloudDiskRootPath(data->userId);
133     } else {
134         auto inoPtr = FileOperationsHelper::FindCloudDiskInode(data, static_cast<int64_t>(ino));
135         if (inoPtr == nullptr) {
136             fuse_reply_err(req, EINVAL);
137             LOGE("inode not found");
138             return;
139         }
140         path = inoPtr->path;
141     }
142     DIR* dir = opendir(path.c_str());
143     if (dir == NULL) {
144         LOGE("opendir error %{public}d, path:%{public}s", errno, GetAnonyString(path).c_str());
145         return;
146     }
147 
148     struct dirent *entry;
149     string entryData;
150     size_t len = 0;
151     while ((entry = readdir(dir)) != NULL) {
152         if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
153             continue;
154         }
155 
156         string childPath = FileOperationsHelper::GetCloudDiskLocalPath(data->userId,
157             entry->d_name);
158         int64_t key = FileOperationsHelper::FindLocalId(data, std::to_string(ino) +
159             entry->d_name);
160         auto childPtr = FileOperationsHelper::FindCloudDiskInode(data, key);
161         if (childPtr == nullptr) {
162             childPtr = FileOperationsHelper::GenerateCloudDiskInode(data, ino,
163                 entry->d_name, childPath.c_str());
164         }
165         if (childPtr == nullptr) {
166             continue;
167         }
168         FileOperationsHelper::AddDirEntry(req, entryData, len, entry->d_name, childPtr);
169     }
170     FileOperationsHelper::FuseReplyLimited(req, entryData.c_str(), len, off, size);
171     closedir(dir);
172     return;
173 }
174 } // namespace CloudDisk
175 } // namespace FileManagement
176 } // namespace OHOS
177