• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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