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 0xD001600
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
GetSize(const std::string & uri,bool isSrcUri,uint64_t & size)39 int32_t FileSizeUtils::GetSize(const std::string &uri, bool isSrcUri, uint64_t &size)
40 {
41 auto path = GetPathFromUri(uri, isSrcUri);
42 if (path.empty()) {
43 return ERR_BAD_VALUE;
44 }
45
46 bool isDirectory;
47 auto ret = IsDirectory(uri, isSrcUri, isDirectory);
48 if (ret != E_OK) {
49 return ret;
50 }
51 if (isDirectory) {
52 return GetDirSize(path, size);
53 } else {
54 return GetFileSize(path, size);
55 }
56 }
57
IsDirectory(const std::string & uri,bool isSrcUri,bool & isDirectory)58 int32_t FileSizeUtils::IsDirectory(const std::string &uri, bool isSrcUri, bool &isDirectory)
59 {
60 auto path = GetPathFromUri(uri, isSrcUri);
61 if (path.empty()) {
62 return ERR_BAD_VALUE;
63 }
64
65 bool isDir = false;
66 auto ret = IsDirectory(path, isDir);
67 if (ret != E_OK) {
68 return ret;
69 }
70
71 bool isFile = false;
72 ret = IsFile(path, isFile);
73 if (ret != E_OK) {
74 return ret;
75 }
76
77 if (isDir == isFile) {
78 return ERR_BAD_VALUE;
79 }
80 isDirectory = isDir;
81 return E_OK;
82 }
83
FilterFunc(const struct dirent * filename)84 int FileSizeUtils::FilterFunc(const struct dirent *filename)
85 {
86 if (std::string_view(filename->d_name) == "." || std::string_view(filename->d_name) == "..") {
87 return DISMATCH;
88 }
89 return MATCH;
90 }
91
Deleter(struct NameList * arg)92 void FileSizeUtils::Deleter(struct NameList *arg)
93 {
94 for (int i = 0; i < arg->direntNum; i++) {
95 free((arg->namelist)[i]);
96 (arg->namelist)[i] = nullptr;
97 }
98 free(arg->namelist);
99 arg->namelist = nullptr;
100 delete arg;
101 arg = nullptr;
102 }
103
GetDirNameList(const std::string & path)104 std::unique_ptr<struct NameList, decltype(FileSizeUtils::Deleter) *> FileSizeUtils::GetDirNameList(
105 const std::string &path)
106 {
107 std::unique_ptr<struct NameList, decltype(Deleter) *> pNameList = { new (std::nothrow) struct NameList, Deleter };
108 if (pNameList == nullptr) {
109 LOGE("Failed to request heap memory.");
110 return pNameList;
111 }
112 int num = scandir(path.c_str(), &(pNameList->namelist), FilterFunc, alphasort);
113 pNameList->direntNum = num;
114 return pNameList;
115 }
116
GetFileSize(const std::string & path,uint64_t & size)117 int32_t FileSizeUtils::GetFileSize(const std::string &path, uint64_t &size)
118 {
119 struct stat buf {};
120 int ret = stat(path.c_str(), &buf);
121 if (ret == -1) {
122 LOGI("Stat failed.");
123 size = 0;
124 return errno;
125 }
126 size = static_cast<uint64_t>(buf.st_size);
127 return E_OK;
128 }
129
GetDirSize(const std::string & path,uint64_t & size)130 int32_t FileSizeUtils::GetDirSize(const std::string &path, uint64_t &size)
131 {
132 auto pNameList = GetDirNameList(path);
133 if (pNameList == nullptr) {
134 return ENOMEM;
135 }
136 size = 0;
137 for (int i = 0; i < pNameList->direntNum; i++) {
138 std::string dest = path + '/' + std::string((pNameList->namelist[i])->d_name);
139 if ((pNameList->namelist[i])->d_type == DT_LNK) {
140 continue;
141 }
142 if ((pNameList->namelist[i])->d_type == DT_DIR) {
143 uint64_t subSize = 0;
144 auto err = GetDirSize(dest, subSize);
145 if (err != E_OK) {
146 LOGE("GetDirSize failed, path is %{public}s", dest.c_str());
147 return err;
148 }
149 size += subSize;
150 } else {
151 struct stat st {};
152 if (stat(dest.c_str(), &st) == -1) {
153 return errno;
154 }
155 size += static_cast<uint64_t>(st.st_size);
156 }
157 }
158 return E_OK;
159 }
160
IsFile(const std::string & path,bool & result)161 int32_t FileSizeUtils::IsFile(const std::string &path, bool &result)
162 {
163 struct stat buf {};
164 int ret = stat(path.c_str(), &buf);
165 if (ret == -1) {
166 return errno;
167 }
168 result = (buf.st_mode & S_IFMT) == S_IFREG;
169 return E_OK;
170 }
171
IsDirectory(const std::string & path,bool & result)172 int32_t FileSizeUtils::IsDirectory(const std::string &path, bool &result)
173 {
174 struct stat buf {};
175 int ret = stat(path.c_str(), &buf);
176 if (ret == -1) {
177 return errno;
178 }
179 result = (buf.st_mode & S_IFMT) == S_IFDIR;
180 return E_OK;
181 }
182
GetPathFromUri(const std::string & uri,bool isSrcUri)183 std::string FileSizeUtils::GetPathFromUri(const std::string &uri, bool isSrcUri)
184 {
185 std::string path;
186 FileUri fileUri(uri);
187 if (isSrcUri) {
188 path = GetRealPath(fileUri.GetRealPath());
189 } else {
190 path = GetRealPath(fileUri.GetPath());
191 }
192 return path;
193 }
194
GetRealPath(const std::string & path)195 std::string FileSizeUtils::GetRealPath(const std::string &path)
196 {
197 std::filesystem::path tempPath(path);
198 std::filesystem::path realPath{};
199 for (const auto& component : tempPath) {
200 if (component == ".") {
201 continue;
202 } else if (component == "..") {
203 realPath = realPath.parent_path();
204 } else {
205 realPath /= component;
206 }
207 }
208 return realPath.string();
209 }
210 } // namespace DistributedFile
211 } // namespace Storage
212 } // namespace OHOS
213