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 #define MLOG_TAG "Scanner"
16
17 #include "scanner_utils.h"
18
19 #include <cerrno>
20 #include <fstream>
21
22 #include "directory_ex.h"
23
24 #include "media_log.h"
25
26 namespace OHOS {
27 namespace Media {
28 using namespace std;
29
30 std::vector<size_t> ScannerUtils::skipList_;
31
32 // Check if file exists or not
IsExists(const string & path)33 bool ScannerUtils::IsExists(const string &path)
34 {
35 struct stat statInfo {};
36
37 if (path.empty()) {
38 MEDIA_ERR_LOG("Given path name is empty");
39 return false;
40 }
41
42 return ((stat(path.c_str(), &statInfo)) == ERR_SUCCESS);
43 }
44
45 // Get the file name from file URI
GetFileNameFromUri(const string & path)46 string ScannerUtils::GetFileNameFromUri(const string &path)
47 {
48 if (!path.empty()) {
49 size_t lastSlashPosition = path.rfind("/");
50 if (lastSlashPosition != string::npos) {
51 if (path.size() > lastSlashPosition) {
52 return path.substr(lastSlashPosition + 1);
53 }
54 }
55 }
56
57 MEDIA_ERR_LOG("Failed to obtain file name because given pathname is empty");
58 return "";
59 }
60
61 // Get file extension from the given filepath uri
GetFileExtensionFromFileUri(const string & path)62 string ScannerUtils::GetFileExtensionFromFileUri(const string &path)
63 {
64 if (!path.empty()) {
65 size_t dotIndex = path.rfind(".");
66 if (dotIndex != string::npos) {
67 return path.substr(dotIndex + 1);
68 }
69 }
70
71 MEDIA_ERR_LOG("Failed to obtain file extension because given pathname is empty");
72 return "";
73 }
74
GetMediatypeFromMimetype(const string & mimetype)75 MediaType ScannerUtils::GetMediatypeFromMimetype(const string &mimetype)
76 {
77 MediaType mediaType = MEDIA_TYPE_FILE;
78
79 if (!mimetype.empty()) {
80 if (mimetype == DEFAULT_AUDIO_MIME_TYPE) {
81 mediaType = MEDIA_TYPE_AUDIO;
82 } else if (mimetype == DEFAULT_VIDEO_MIME_TYPE) {
83 mediaType = MEDIA_TYPE_VIDEO;
84 } else if (mimetype == DEFAULT_IMAGE_MIME_TYPE) {
85 mediaType = MEDIA_TYPE_IMAGE;
86 }
87 }
88
89 return mediaType;
90 }
91
92 // Obtain Mime type from the file extension
GetMimeTypeFromExtension(const string & extension)93 string ScannerUtils::GetMimeTypeFromExtension(const string &extension)
94 {
95 string mimeType = DEFAULT_FILE_MIME_TYPE;
96 string extn = extension;
97
98 if (extn.empty()) {
99 MEDIA_ERR_LOG("Given file extension is empty");
100 return mimeType;
101 }
102
103 transform(extn.begin(), extn.end(), extn.begin(), ::tolower);
104 if (SUPPORTED_AUDIO_FORMATS_SET.find(extn) != SUPPORTED_AUDIO_FORMATS_SET.end()) {
105 mimeType = DEFAULT_AUDIO_MIME_TYPE;
106 } else if (SUPPORTED_VIDEO_FORMATS_SET.find(extn) != SUPPORTED_VIDEO_FORMATS_SET.end()) {
107 mimeType = DEFAULT_VIDEO_MIME_TYPE;
108 } else if (SUPPORTED_IMAGE_FORMATS_SET.find(extn) != SUPPORTED_IMAGE_FORMATS_SET.end()) {
109 mimeType = DEFAULT_IMAGE_MIME_TYPE;
110 }
111
112 return mimeType;
113 }
114
115 // Check if the given path is a directory path
IsDirectory(const string & path)116 bool ScannerUtils::IsDirectory(const string &path)
117 {
118 struct stat s;
119
120 if (!path.empty()) {
121 if (stat(path.c_str(), &s) == 0) {
122 if (s.st_mode & S_IFDIR) {
123 return true;
124 }
125 }
126 }
127
128 MEDIA_ERR_LOG("Either path is empty or it is not a directory");
129 return false;
130 }
131
132 // Check if the given file starts with '.' , i.e. if it is hidden
IsFileHidden(const string & path)133 bool ScannerUtils::IsFileHidden(const string &path)
134 {
135 if (!path.empty()) {
136 string fileName = GetFileNameFromUri(path);
137 if (!fileName.empty() && fileName.at(0) == '.') {
138 return true;
139 }
140 }
141
142 MEDIA_ERR_LOG("Either filepath is empty or it is not hidden");
143 return false;
144 }
145
146 // Get the parent path
GetParentPath(const string & path)147 string ScannerUtils::GetParentPath(const string &path)
148 {
149 if (!path.empty()) {
150 size_t lastSlashPosition = path.rfind("/");
151 if (lastSlashPosition != string::npos && path.size() > lastSlashPosition) {
152 return path.substr(0, lastSlashPosition);
153 }
154 }
155
156 MEDIA_ERR_LOG("Failed to obtain the parent path");
157 return "";
158 }
159
GetRootMediaDir(string & dir)160 void ScannerUtils::GetRootMediaDir(string &dir)
161 {
162 dir = ROOT_MEDIA_DIR;
163 }
164
GetFileTitle(const string & displayName)165 string ScannerUtils::GetFileTitle(const string &displayName)
166 {
167 string title = "";
168 if (!displayName.empty()) {
169 string::size_type pos = displayName.find_first_of('.');
170 if (pos == displayName.length()) {
171 return displayName;
172 }
173 title = displayName.substr(0, pos);
174 }
175 return title;
176 }
177
IsDirHidden(const string & path)178 bool ScannerUtils::IsDirHidden(const string &path)
179 {
180 bool dirHid = false;
181
182 if (!path.empty()) {
183 string dirName = ScannerUtils::GetFileNameFromUri(path);
184 if (!dirName.empty() && dirName.at(0) == '.') {
185 MEDIA_ERR_LOG("Directory is of hidden type");
186 return true;
187 }
188
189 string curPath = path;
190 string excludePath = curPath.append("/.nomedia");
191 // Check is the folder consist of .nomedia file
192 if (ScannerUtils::IsExists(excludePath)) {
193 return true;
194 }
195
196 // Check is the dir is part of skiplist
197 if (CheckSkipScanList(path)) {
198 return true;
199 }
200 }
201
202 return dirHid;
203 }
204
IsDirHiddenRecursive(const string & path)205 bool ScannerUtils::IsDirHiddenRecursive(const string &path)
206 {
207 bool dirHid = false;
208 string curPath = path;
209
210 do {
211 dirHid = IsDirHidden(curPath);
212 if (dirHid) {
213 break;
214 }
215
216 curPath = ScannerUtils::GetParentPath(curPath);
217 if (curPath.empty()) {
218 break;
219 }
220 } while (true);
221
222 return dirHid;
223 }
224
225 // Initialize the skip list
InitSkipList()226 void ScannerUtils::InitSkipList()
227 {
228 hash<string> hashStr;
229 size_t hashPath;
230 string path;
231
232 /*
233 * 1. file path: in disk or hard code? path?
234 * 2. call_once: no need to init again if it is really empty
235 * 3. add lock
236 */
237 ifstream skipFile(SKIPLIST_FILE_PATH.c_str());
238 if (skipFile.is_open()) {
239 while (getline(skipFile, path)) {
240 hashPath = hashStr(path);
241 skipList_.insert(skipList_.begin(), hashPath);
242 }
243 skipFile.close();
244 }
245
246 return;
247 }
248
249 // Check if path is part of Skip scan list
CheckSkipScanList(const string & path)250 bool ScannerUtils::CheckSkipScanList(const string &path)
251 {
252 hash<string> hashStr;
253 size_t hashPath;
254
255 if (skipList_.empty()) {
256 InitSkipList();
257 }
258
259 hashPath = hashStr(path);
260 if (find(skipList_.begin(), skipList_.end(), hashPath) != skipList_.end()) {
261 return true;
262 }
263
264 return false;
265 }
266 } // namespace Media
267 } // namespace OHOS
268