• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (c) 2025 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 
16 #include "copy/remote_file_copy_manager.h"
17 
18 #include <mutex>
19 #include <sys/stat.h>
20 
21 #include "copy/file_size_utils.h"
22 #include "dfs_error.h"
23 #include "datashare_helper.h"
24 #include "ipc_skeleton.h"
25 #include "sandbox_helper.h"
26 #include "utils_log.h"
27 
28 #undef LOG_DOMAIN
29 #undef LOG_TAG
30 #define LOG_DOMAIN 0xD004315
31 #define LOG_TAG "distributedfile_daemon"
32 
33 namespace OHOS {
34 namespace Storage {
35 namespace DistributedFile {
36 using namespace AppFileService;
37 using namespace FileManagement;
38 static const std::string MEDIA_AUTHORITY = "media";
39 static const std::string FILE_MANAGER_AUTHORITY = "docs";
40 static const std::string FILE_SCHEMA = "file://";
41 static const std::string FILE_SEPARATOR = "/";
42 std::shared_ptr<RemoteFileCopyManager> RemoteFileCopyManager::instance_ = nullptr;
43 
GetBundleName(const std::string & uri)44 static std::string GetBundleName(const std::string &uri)
45 {
46     auto pos = uri.find(FILE_SCHEMA);
47     if (pos == std::string::npos) {
48         return "";
49     }
50     auto tmpUri = uri.substr(pos + FILE_SCHEMA.size());
51     if (tmpUri.empty()) {
52         return "";
53     }
54     auto bundleNamePos = tmpUri.find(FILE_SEPARATOR);
55     if (bundleNamePos == std::string::npos) {
56         return "";
57     }
58     return tmpUri.substr(0, bundleNamePos);
59 }
60 
ChangeOwnerRecursive(const std::string & path,uid_t uid,gid_t gid)61 static int32_t ChangeOwnerRecursive(const std::string &path, uid_t uid, gid_t gid)
62 {
63     std::unique_ptr<DIR, decltype(&closedir)> dir(opendir(path.c_str()), &closedir);
64     if (dir == nullptr) {
65         LOGE("Directory is null");
66         return EINVAL;
67     }
68 
69     struct dirent *entry = nullptr;
70     while ((entry = readdir(dir.get())) != nullptr) {
71         if (entry->d_type == DT_DIR) {
72             if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) {
73                 continue;
74             }
75             std::string subPath = path + "/" + entry->d_name;
76             if (chown(subPath.c_str(), uid, gid) == -1) {
77                 LOGE("Change owner recursive failed");
78                 return EIO;
79             }
80             return ChangeOwnerRecursive(subPath, uid, gid);
81         } else {
82             std::string filePath = path + "/" + entry->d_name;
83             if (chown(filePath.c_str(), uid, gid) == -1) {
84                 LOGE("Change owner recursive failed");
85                 return EIO;
86             }
87         }
88     }
89     return E_OK;
90 }
91 
IsMediaUri(const std::string & uriPath)92 bool RemoteFileCopyManager::IsMediaUri(const std::string &uriPath)
93 {
94     Uri uri(uriPath);
95     std::string bundleName = uri.GetAuthority();
96     return bundleName == MEDIA_AUTHORITY;
97 }
98 
IsFile(const std::string & path)99 bool RemoteFileCopyManager::IsFile(const std::string &path)
100 {
101     struct stat buf {};
102     int ret = stat(path.c_str(), &buf);
103     if (ret == -1) {
104         LOGE("stat failed, errno is %{public}d, ", errno);
105         return false;
106     }
107     return (buf.st_mode & S_IFMT) == S_IFREG;
108 }
109 
GetFileName(const std::string & path)110 static std::string GetFileName(const std::string &path)
111 {
112     auto pos = path.rfind("/");
113     if (pos == std::string::npos) {
114         LOGE("invalid path");
115         return "";
116     }
117     return path.substr(pos + 1);
118 }
119 
GetInstance()120 std::shared_ptr<RemoteFileCopyManager> RemoteFileCopyManager::GetInstance()
121 {
122     static std::once_flag once;
123     std::call_once(once, []() {
124         RemoteFileCopyManager::instance_ = std::make_shared<RemoteFileCopyManager>();
125     });
126     return instance_;
127 }
128 
AddFileInfos(std::shared_ptr<FileInfos> infos)129 void RemoteFileCopyManager::AddFileInfos(std::shared_ptr<FileInfos> infos)
130 {
131     std::lock_guard<std::mutex> lock(FileInfosVecMutex_);
132     FileInfosVec_.push_back(infos);
133 }
134 
CreateFileInfos(const std::string & srcUri,const std::string & destUri,std::shared_ptr<FileInfos> & infos,const int32_t userId,const std::string & copyPath)135 int32_t RemoteFileCopyManager::CreateFileInfos(const std::string &srcUri,
136     const std::string &destUri, std::shared_ptr<FileInfos> &infos, const int32_t userId, const std::string &copyPath)
137 {
138     infos->srcUri = srcUri;
139     infos->destUri = destUri;
140     std::string srcPhysicalPath;
141     if (SandboxHelper::GetPhysicalPath(srcUri, std::to_string(userId), srcPhysicalPath)) {
142         LOGE("Get src path failed, invalid uri");
143         return EINVAL;
144     }
145     std::string dstPhysicalPath;
146     if (SandboxHelper::GetPhysicalPath(destUri, std::to_string(userId), dstPhysicalPath)) {
147         LOGE("Get dst path failed, invalid uri");
148         return EINVAL;
149     }
150     Uri uri(destUri);
151     auto authority = uri.GetAuthority();
152     if (authority != FILE_MANAGER_AUTHORITY && authority != MEDIA_AUTHORITY) {
153         std::string bundleName = GetBundleName(destUri);
154         std::string fileName = GetFileName(srcPhysicalPath);
155         // copy to tmp path
156         dstPhysicalPath = "/data/service/el2/" + std::to_string(userId) + "/hmdfs/account/data/" + bundleName +
157             "/" + copyPath + "/" + fileName;
158     }
159     infos->srcPath = srcPhysicalPath;
160     infos->destPath = dstPhysicalPath;
161     infos->srcUriIsFile = IsMediaUri(infos->srcUri) || IsFile(infos->srcPath);
162     infos->callingUid = IPCSkeleton::GetCallingUid();
163     AddFileInfos(infos);
164     return E_OK;
165 }
166 
RemoveFileInfos(std::shared_ptr<FileInfos> infos)167 void RemoteFileCopyManager::RemoveFileInfos(std::shared_ptr<FileInfos> infos)
168 {
169     std::lock_guard<std::mutex> lock(FileInfosVecMutex_);
170     for (auto it = FileInfosVec_.begin(); it != FileInfosVec_.end();) {
171         if ((*it)->srcUri == infos->srcUri && (*it)->destUri == infos->destUri) {
172             it = FileInfosVec_.erase(it);
173         } else {
174             ++it;
175         }
176     }
177 }
178 
RemoteCancel(const std::string & srcUri,const std::string & destUri)179 int32_t RemoteFileCopyManager::RemoteCancel(const std::string &srcUri, const std::string &destUri)
180 {
181     LOGI("RemoteCancel");
182     std::lock_guard<std::mutex> lock(FileInfosVecMutex_);
183     int32_t ret = 0;
184     if (!FileSizeUtils::IsFilePathValid(FileSizeUtils::GetRealUri(srcUri)) ||
185         !FileSizeUtils::IsFilePathValid(FileSizeUtils::GetRealUri(destUri))) {
186         LOGE("path is forbidden");
187         return EINVAL;
188     }
189     for (auto item = FileInfosVec_.begin(); item != FileInfosVec_.end();) {
190         if ((*item)->srcUri != srcUri || (*item)->destUri != destUri) {
191             ++item;
192             continue;
193         }
194         auto callingUid = IPCSkeleton::GetCallingUid();
195         if (callingUid != (*item)->callingUid) {
196             LOGE("RemoteCancel failed, calling uid=%{public}d has no permission to cancel copy for uid=%{public}d.",
197             callingUid, (*item)->callingUid);
198             return EPERM;
199         }
200         LOGI("RemoteCancel success");
201         (*item)->needCancel.store(true);
202         item = FileInfosVec_.erase(item);
203         return ret;
204     }
205     return E_OK;
206 }
207 
RemoteCopy(const std::string & srcUri,const std::string & destUri,const sptr<IFileTransListener> & listener,const int32_t userId,const std::string & copyPath)208 int32_t RemoteFileCopyManager::RemoteCopy(const std::string &srcUri, const std::string &destUri,
209     const sptr<IFileTransListener> &listener, const int32_t userId, const std::string &copyPath)
210 {
211     LOGI("RemoteCopy start");
212     if (srcUri.empty() || destUri.empty()) {
213         return EINVAL;
214     }
215     if (!FileSizeUtils::IsFilePathValid(FileSizeUtils::GetRealUri(srcUri)) ||
216         !FileSizeUtils::IsFilePathValid(FileSizeUtils::GetRealUri(destUri))) {
217         LOGE("path is forbidden");
218         return EINVAL;
219     }
220     auto infos = std::make_shared<FileInfos>();
221     auto ret = CreateFileInfos(srcUri, destUri, infos, userId, copyPath);
222     if (ret != E_OK) {
223         LOGE("CreateFileInfos failed,ret= %{public}d", ret);
224         return ret;
225     }
226     std::function<void(uint64_t processSize, uint64_t totalSize)> processCallback =
227         [&listener](uint64_t processSize, uint64_t totalSize) -> void {
228         if (processSize != totalSize) {
229             listener->OnFileReceive(totalSize, processSize);
230         }
231     };
232     infos->localListener = FileCopyLocalListener::GetLocalListener(infos->srcPath,
233         infos->srcUriIsFile, processCallback);
234     auto result = FileCopyManager::GetInstance()->ExecLocal(infos);
235     if (ChangeOwnerRecursive(infos->destPath, infos->callingUid, infos->callingUid) != 0) {
236         LOGE("ChangeOwnerRecursive failed, calling uid= %{public}d", infos->callingUid);
237     }
238     RemoveFileInfos(infos);
239     infos->localListener->StopListener();
240 
241     if (result != E_OK) {
242         return result;
243     }
244     result = infos->localListener->GetResult();
245     if (result != E_OK) {
246         listener->OnFailed("", result);
247         return result;
248     }
249     listener->OnFinished("");
250     LOGI("RemoteCopy end");
251     return E_OK;
252 }
253 } // namespace DistributedFile
254 } // namespace Storage
255 } // namespace OHOS
256