• 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/file_size_utils.h"
17 
18 #include <sys/stat.h>
19 #include <filesystem>
20 
21 #include "dfs_error.h"
22 #include "file_uri.h"
23 #include "utils_log.h"
24 
25 #undef LOG_DOMAIN
26 #undef LOG_TAG
27 #define LOG_DOMAIN 0xD004315
28 #define LOG_TAG "distributedfile_daemon"
29 
30 namespace OHOS {
31 namespace Storage {
32 namespace DistributedFile {
33 using namespace AppFileService;
34 using namespace AppFileService::ModuleFileUri;
35 using namespace FileManagement;
36 static constexpr int DISMATCH = 0;
37 static constexpr int MATCH = 1;
38 static constexpr char PATH_INVALID_FLAG1[] = "../";
39 static constexpr char PATH_INVALID_FLAG2[] = "/..";
40 static const uint32_t PATH_INVALID_FLAG_LEN = 3;
41 static const char FILE_SEPARATOR_CHAR = '/';
42 static constexpr char NETWORK_ID[] = "?networkid=";
43 
GetSize(const std::string & uri,bool isSrcUri,uint64_t & size)44 int32_t FileSizeUtils::GetSize(const std::string &uri, bool isSrcUri, uint64_t &size)
45 {
46     if (!IsFilePathValid(GetRealUri(uri))) {
47         LOGE("path is forbidden");
48         return OHOS::FileManagement::E_ILLEGAL_URI;
49     }
50     auto path = GetPathFromUri(uri, isSrcUri);
51     if (path.empty()) {
52         return ERR_BAD_VALUE;
53     }
54 
55     bool isDirectory;
56     auto ret = IsDirectory(uri, isSrcUri, isDirectory);
57     if (ret != E_OK) {
58         return ret;
59     }
60     if (isDirectory) {
61         return GetDirSize(path, size);
62     } else {
63         return GetFileSize(path, size);
64     }
65 }
66 
IsDirectory(const std::string & uri,bool isSrcUri,bool & isDirectory)67 int32_t FileSizeUtils::IsDirectory(const std::string &uri, bool isSrcUri, bool &isDirectory)
68 {
69     if (!IsFilePathValid(GetRealUri(uri))) {
70         LOGE("path is forbidden");
71         return OHOS::FileManagement::E_ILLEGAL_URI;
72     }
73     auto path = GetPathFromUri(uri, isSrcUri);
74     if (path.empty()) {
75         return ERR_BAD_VALUE;
76     }
77 
78     bool isDir = false;
79     auto ret = IsDirectory(path, isDir);
80     if (ret != E_OK) {
81         return ret;
82     }
83 
84     bool isFile = false;
85     ret = IsFile(path, isFile);
86     if (ret != E_OK) {
87         return ret;
88     }
89 
90     if (isDir == isFile) {
91         return ERR_BAD_VALUE;
92     }
93     isDirectory = isDir;
94     return E_OK;
95 }
96 
FilterFunc(const struct dirent * filename)97 int FileSizeUtils::FilterFunc(const struct dirent *filename)
98 {
99     if (std::string_view(filename->d_name) == "." || std::string_view(filename->d_name) == "..") {
100         return DISMATCH;
101     }
102     return MATCH;
103 }
104 
Deleter(struct NameList * arg)105 void FileSizeUtils::Deleter(struct NameList *arg)
106 {
107     for (int i = 0; i < arg->direntNum; i++) {
108         if ((arg->namelist)[i]) {
109             free((arg->namelist)[i]);
110         }
111         (arg->namelist)[i] = nullptr;
112     }
113     free(arg->namelist);
114     arg->namelist = nullptr;
115     delete arg;
116     arg = nullptr;
117 }
118 
GetDirNameList(const std::string & path)119 std::unique_ptr<struct NameList, decltype(FileSizeUtils::Deleter) *> FileSizeUtils::GetDirNameList(
120     const std::string &path)
121 {
122     std::unique_ptr<struct NameList, decltype(Deleter) *> pNameList = { new (std::nothrow) struct NameList, Deleter };
123     if (pNameList == nullptr) {
124         LOGE("Failed to request heap memory.");
125         return pNameList;
126     }
127     int num = scandir(path.c_str(), &(pNameList->namelist), FilterFunc, alphasort);
128     pNameList->direntNum = num;
129     return pNameList;
130 }
131 
GetFileSize(const std::string & path,uint64_t & size)132 int32_t FileSizeUtils::GetFileSize(const std::string &path, uint64_t &size)
133 {
134     struct stat buf {};
135     int ret = stat(path.c_str(), &buf);
136     if (ret == -1) {
137         LOGI("Stat failed.");
138         size = 0;
139         return errno;
140     }
141     size = static_cast<uint64_t>(buf.st_size);
142     return E_OK;
143 }
144 
GetDirSize(const std::string & path,uint64_t & size)145 int32_t FileSizeUtils::GetDirSize(const std::string &path, uint64_t &size)
146 {
147     auto pNameList = GetDirNameList(path);
148     if (pNameList == nullptr) {
149         return ENOMEM;
150     }
151     size = 0;
152     for (int i = 0; i < pNameList->direntNum; i++) {
153         if ((pNameList->namelist[i]) == nullptr) {
154             continue;
155         }
156         std::string dest = path + '/' + std::string((pNameList->namelist[i])->d_name);
157         if ((pNameList->namelist[i])->d_type == DT_LNK) {
158             continue;
159         }
160         if ((pNameList->namelist[i])->d_type == DT_DIR) {
161             uint64_t subSize = 0;
162             auto err = GetDirSize(dest, subSize);
163             if (err != E_OK) {
164                 LOGE("GetDirSize failed");
165                 return err;
166             }
167             size += subSize;
168         } else {
169             struct stat st {};
170             if (stat(dest.c_str(), &st) == -1) {
171                 return errno;
172             }
173             size += static_cast<uint64_t>(st.st_size);
174         }
175     }
176     return E_OK;
177 }
178 
IsFile(const std::string & path,bool & result)179 int32_t FileSizeUtils::IsFile(const std::string &path, bool &result)
180 {
181     struct stat buf {};
182     int ret = stat(path.c_str(), &buf);
183     if (ret == -1) {
184         return errno;
185     }
186     result = (buf.st_mode & S_IFMT) == S_IFREG;
187     return E_OK;
188 }
189 
IsDirectory(const std::string & path,bool & result)190 int32_t FileSizeUtils::IsDirectory(const std::string &path, bool &result)
191 {
192     struct stat buf {};
193     int ret = stat(path.c_str(), &buf);
194     if (ret == -1) {
195         return errno;
196     }
197     result = (buf.st_mode & S_IFMT) == S_IFDIR;
198     return E_OK;
199 }
200 
GetPathFromUri(const std::string & uri,bool isSrcUri)201 std::string FileSizeUtils::GetPathFromUri(const std::string &uri, bool isSrcUri)
202 {
203     std::string path;
204     FileUri fileUri(uri);
205     if (isSrcUri) {
206         path = GetRealPath(fileUri.GetRealPath());
207     } else {
208         path = GetRealPath(fileUri.GetPath());
209     }
210     return path;
211 }
212 
GetRealPath(const std::string & path)213 std::string FileSizeUtils::GetRealPath(const std::string &path)
214 {
215     std::filesystem::path tempPath(path);
216     std::filesystem::path realPath{};
217     for (const auto& component : tempPath) {
218         if (component == ".") {
219             continue;
220         } else if (component == "..") {
221             realPath = realPath.parent_path();
222         } else {
223             realPath /= component;
224         }
225     }
226     return realPath.string();
227 }
228 
GetRealUri(const std::string & uri)229 std::string FileSizeUtils::GetRealUri(const std::string &uri)
230 {
231     std::string realUri = uri;
232     auto pos = uri.find(NETWORK_ID);
233     if (pos != std::string::npos) {
234         realUri = uri.substr(0, pos);
235     }
236     return realUri;
237 }
238 
IsFilePathValid(const std::string & filePath)239 bool FileSizeUtils::IsFilePathValid(const std::string &filePath)
240 {
241     size_t pos = filePath.find(PATH_INVALID_FLAG1);
242     while (pos != std::string::npos) {
243         if (pos == 0 || filePath[pos - 1] == FILE_SEPARATOR_CHAR) {
244             LOGE("Relative path is not allowed, path contain ../");
245             return false;
246         }
247         pos = filePath.find(PATH_INVALID_FLAG1, pos + PATH_INVALID_FLAG_LEN);
248     }
249     pos = filePath.rfind(PATH_INVALID_FLAG2);
250     if ((pos != std::string::npos) && (filePath.size() - pos == PATH_INVALID_FLAG_LEN)) {
251         LOGE("Relative path is not allowed, path tail is /..");
252         return false;
253     }
254     return true;
255 }
256 } // namespace DistributedFile
257 } // namespace Storage
258 } // namespace OHOS
259