1 /*
2 * Copyright (C) 2021 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 "media_file_utils.h"
17
18 #include <regex>
19 #include <cerrno>
20
21 #include "media_data_ability_const.h"
22 #include "media_lib_service_const.h"
23 #include "media_log.h"
24
25 using namespace std;
26
27 namespace OHOS {
28 namespace Media {
UnlinkCb(const char * fpath,const struct stat * sb,int32_t typeflag,struct FTW * ftwbuf)29 int32_t UnlinkCb(const char *fpath, const struct stat *sb, int32_t typeflag, struct FTW *ftwbuf)
30 {
31 int32_t errRet = remove(fpath);
32 if (errRet) {
33 perror(fpath);
34 }
35
36 return errRet;
37 }
38
RemoveDirectory(const string & path)39 int32_t RemoveDirectory(const string &path)
40 {
41 int32_t errCode;
42 char *dirPath = const_cast<char*>(path.c_str());
43
44 errCode = nftw(dirPath, UnlinkCb, OPEN_FDS, FTW_DEPTH | FTW_PHYS);
45 return errCode;
46 }
47
CreateDirectory(const string & dirPath)48 bool MediaFileUtils::CreateDirectory(const string& dirPath)
49 {
50 string subStr;
51 string segment;
52
53 /* Create directory and its sub directories if does not exist
54 * take each string after '/' create directory if does not exist.
55 * Created directory will be the base path for the next sub directory.
56 */
57
58 stringstream folderStream(dirPath.c_str());
59 while (std::getline(folderStream, segment, '/')) {
60 if (segment == "") // skip the first "/" in case of "/storage/media/local/files"
61 continue;
62
63 subStr = subStr + SLASH_CHAR + segment;
64 if (!IsDirectory(subStr)) {
65 string folderPath = subStr;
66 mode_t mask = umask(0);
67 if (mkdir(folderPath.c_str(), CHOWN_RWX_USR_GRP) == -1) {
68 MEDIA_ERR_LOG("Failed to create directory %{public}d", errno);
69 umask(mask);
70 return false;
71 }
72 umask(mask);
73 }
74 }
75
76 return true;
77 }
78
IsFileExists(const string & fileName)79 bool MediaFileUtils::IsFileExists(const string &fileName)
80 {
81 struct stat statInfo {};
82
83 return ((stat(fileName.c_str(), &statInfo)) == SUCCESS);
84 }
85
GetFilename(const string & filePath)86 string MediaFileUtils::GetFilename(const string &filePath)
87 {
88 string fileName = "";
89
90 if (!(filePath.empty())) {
91 size_t lastSlash = filePath.rfind("/");
92 if (lastSlash != string::npos) {
93 if (filePath.size() > lastSlash) {
94 fileName = filePath.substr(lastSlash + 1, filePath.length() - lastSlash);
95 }
96 }
97 }
98
99 return fileName;
100 }
101
IsDirectory(const string & dirName)102 bool MediaFileUtils::IsDirectory(const string &dirName)
103 {
104 struct stat statInfo {};
105 if (stat(dirName.c_str(), &statInfo) == SUCCESS) {
106 if (statInfo.st_mode & S_IFDIR) {
107 return true;
108 }
109 }
110
111 return false;
112 }
113
CreateFile(const string & filePath)114 bool MediaFileUtils::CreateFile(const string &filePath)
115 {
116 bool errCode = false;
117
118 if (filePath.empty() || IsFileExists(filePath)) {
119 return errCode;
120 }
121
122 ofstream file(filePath);
123 if (!file) {
124 MEDIA_ERR_LOG("Output file path could not be created");
125 return errCode;
126 }
127
128 if (chmod(filePath.c_str(), CHOWN_RW_USR_GRP) == SUCCESS) {
129 errCode = true;
130 }
131
132 file.close();
133
134 return errCode;
135 }
136
DeleteFile(const string & fileName)137 bool MediaFileUtils::DeleteFile(const string &fileName)
138 {
139 return (remove(fileName.c_str()) == SUCCESS);
140 }
141
DeleteDir(const std::string & dirName)142 bool MediaFileUtils::DeleteDir(const std::string &dirName)
143 {
144 bool errRet = false;
145
146 if (IsDirectory(dirName)) {
147 errRet = (RemoveDirectory(dirName) == SUCCESS);
148 }
149
150 return errRet;
151 }
152
MoveFile(const string & oldPath,const string & newPath)153 bool MediaFileUtils::MoveFile(const string &oldPath, const string &newPath)
154 {
155 bool errRet = false;
156
157 if (IsFileExists(oldPath) && !IsFileExists(newPath)) {
158 errRet = (rename(oldPath.c_str(), newPath.c_str()) == SUCCESS);
159 }
160
161 return errRet;
162 }
163
CopyFileUtil(const string & filePath,const string & newPath)164 bool CopyFileUtil(const string &filePath, const string &newPath)
165 {
166 struct stat fst;
167 bool errCode = false;
168 char actualPath[PATH_MAX];
169
170 auto absFilePath = realpath(filePath.c_str(), actualPath);
171 if (absFilePath == nullptr) {
172 MEDIA_ERR_LOG("Failed to obtain the canonical path for source path%{public}s %{public}d",
173 filePath.c_str(), errno);
174 return errCode;
175 }
176
177 int32_t source = open(absFilePath, O_RDONLY);
178 if (source == -1) {
179 MEDIA_ERR_LOG("Open failed for source file");
180 return errCode;
181 }
182
183 int32_t dest = open(newPath.c_str(), O_WRONLY | O_CREAT, CHOWN_RWX_USR_GRP);
184 if (dest == -1) {
185 MEDIA_ERR_LOG("Open failed for destination file %{public}d", errno);
186 close(source);
187 return errCode;
188 }
189
190 if (fstat(source, &fst) == SUCCESS) {
191 // Copy file content
192 if (sendfile(dest, source, 0, fst.st_size) != FAIL) {
193 // Copy ownership and mode of source file
194 if (fchown(dest, fst.st_uid, fst.st_gid) == SUCCESS &&
195 fchmod(dest, fst.st_mode) == SUCCESS) {
196 errCode = true;
197 }
198 }
199 }
200
201 close(source);
202 close(dest);
203
204 return errCode;
205 }
206
CopyFile(const string & filePath,const string & newPath)207 bool MediaFileUtils::CopyFile(const string &filePath, const string &newPath)
208 {
209 string newPathCorrected;
210 bool errCode = false;
211
212 if (!(newPath.empty()) && !(filePath.empty())) {
213 newPathCorrected = newPath + "/" + GetFilename(filePath);
214 } else {
215 MEDIA_ERR_LOG("Src filepath or dest filePath value cannot be empty");
216 return false;
217 }
218
219 if (IsFileExists(filePath) == true && !IsFileExists(newPathCorrected)) {
220 errCode = true; // set to create file if directory exists
221 if (!(IsDirectory(newPath))) {
222 errCode = CreateDirectory(newPath);
223 }
224 if (errCode == true) {
225 char actualPath[PATH_MAX];
226 char* canonicalDirPath = realpath(newPath.c_str(), actualPath);
227 if (canonicalDirPath == nullptr) {
228 MEDIA_ERR_LOG("Failed to obtain the canonical path for newpath %{public}s %{public}d",
229 filePath.c_str(), errno);
230 return false;
231 }
232 newPathCorrected = std::string(canonicalDirPath) + "/" + GetFilename(filePath);
233 errCode = CopyFileUtil(filePath, newPathCorrected);
234 }
235 }
236
237 return errCode;
238 }
239
RenameDir(const string & oldPath,const string & newPath)240 bool MediaFileUtils::RenameDir(const string &oldPath, const string &newPath)
241 {
242 bool errRet = false;
243
244 if (IsDirectory(oldPath)) {
245 errRet = (rename(oldPath.c_str(), newPath.c_str()) == SUCCESS);
246 }
247
248 return errRet;
249 }
250
CheckDisplayName(std::string displayName)251 bool MediaFileUtils::CheckDisplayName(std::string displayName)
252 {
253 int size = displayName.length();
254 if (size <= 0 || size > DISPLAYNAME_MAX) {
255 return false;
256 }
257 std::regex express("[\\\\/:*?\"<>|{}\\[\\]]");
258 bool bValid = std::regex_search(displayName, express);
259 if ((displayName.at(0) == '.') || bValid) {
260 MEDIA_ERR_LOG("CheckDisplayName fail %{public}s", displayName.c_str());
261 return false;
262 }
263 return true;
264 }
265
CheckTitle(std::string title)266 bool MediaFileUtils::CheckTitle(std::string title)
267 {
268 int size = title.length();
269 if (size <= 0 || size > DISPLAYNAME_MAX) {
270 return false;
271 }
272 std::regex express("[\\.\\\\/:*?\"<>|{}\\[\\]]");
273 bool bValid = std::regex_search(title, express);
274 if (bValid) {
275 MEDIA_ERR_LOG("CheckTitle title fail %{public}s", title.c_str());
276 }
277 return !bValid;
278 }
279
GetAlbumDateModified(const string & albumPath)280 int64_t MediaFileUtils::GetAlbumDateModified(const string &albumPath)
281 {
282 struct stat statInfo {};
283 if (!albumPath.empty() && stat(albumPath.c_str(), &statInfo) == 0) {
284 return (statInfo.st_mtime);
285 }
286 return 0;
287 }
288
UTCTimeSeconds()289 int64_t MediaFileUtils::UTCTimeSeconds()
290 {
291 struct timespec t;
292 t.tv_sec = 0;
293 t.tv_nsec = 0;
294 clock_gettime(CLOCK_REALTIME, &t);
295 return (int64_t)(t.tv_sec);
296 }
GetNetworkIdFromUri(const string & uri)297 string MediaFileUtils::GetNetworkIdFromUri(const string &uri)
298 {
299 string deviceId;
300 if (uri.empty()) {
301 return deviceId;
302 }
303 size_t pos = uri.find(MEDIALIBRARY_DATA_ABILITY_PREFIX);
304 if (pos == string::npos) {
305 return deviceId;
306 }
307
308 string tempUri = uri.substr(MEDIALIBRARY_DATA_ABILITY_PREFIX.length());
309 if (tempUri.empty()) {
310 return deviceId;
311 }
312 MEDIA_INFO_LOG("MediaFileUtils::GetNetworkIdFromUri tempUri = %{public}s", tempUri.c_str());
313 pos = tempUri.find_first_of('/');
314 if (pos == 0 || pos == string::npos) {
315 return deviceId;
316 }
317 deviceId = tempUri.substr(0, pos);
318 return deviceId;
319 }
320
UpdatePath(const string & path,const string & uri)321 string MediaFileUtils::UpdatePath(const string &path, const string &uri)
322 {
323 string retStr = path;
324 MEDIA_INFO_LOG("MediaFileUtils::UpdatePath path = %{public}s, uri = %{public}s", path.c_str(), uri.c_str());
325 if (path.empty() || uri.empty()) {
326 return retStr;
327 }
328
329 string networkId = GetNetworkIdFromUri(uri);
330 if (networkId.empty()) {
331 MEDIA_INFO_LOG("MediaFileUtils::UpdatePath retStr = %{public}s", retStr.c_str());
332 return retStr;
333 }
334
335 size_t pos = path.find(MEDIA_DATA_DEVICE_PATH);
336 if (pos == string::npos) {
337 return retStr;
338 }
339
340 string beginStr = path.substr(0, pos);
341 if (beginStr.empty()) {
342 return retStr;
343 }
344
345 string endStr = path.substr(pos + MEDIA_DATA_DEVICE_PATH.length());
346 if (beginStr.empty()) {
347 return retStr;
348 }
349
350 retStr = beginStr + networkId + endStr;
351 MEDIA_INFO_LOG("MediaFileUtils::UpdatePath retStr = %{public}s", retStr.c_str());
352 return retStr;
353 }
354 } // namespace Media
355 } // namespace OHOS
356