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 #include "media_column.h"
24 #include "media_log.h"
25 #include "medialibrary_type_const.h"
26 namespace OHOS {
27 namespace Media {
28 using namespace std;
29
30 // Check if file exists or not
IsExists(const string & path)31 bool ScannerUtils::IsExists(const string &path)
32 {
33 struct stat statInfo {};
34
35 if (path.empty()) {
36 MEDIA_ERR_LOG("Given path name is empty");
37 return false;
38 }
39
40 return ((stat(path.c_str(), &statInfo)) == ERR_SUCCESS);
41 }
42
43 // Get the file name from file URI
GetFileNameFromUri(const string & path)44 string ScannerUtils::GetFileNameFromUri(const string &path)
45 {
46 if (!path.empty()) {
47 size_t lastSlashPosition = path.rfind("/");
48 if (lastSlashPosition != string::npos) {
49 if (path.size() > lastSlashPosition) {
50 return path.substr(lastSlashPosition + 1);
51 }
52 }
53 }
54
55 MEDIA_ERR_LOG("Failed to obtain file name because given pathname is empty");
56 return "";
57 }
58
59 // Get file extension from the given filepath or displayName
GetFileExtension(const string & pathOrDisplayName)60 string ScannerUtils::GetFileExtension(const string &pathOrDisplayName)
61 {
62 if (!pathOrDisplayName.empty()) {
63 size_t dotIndex = pathOrDisplayName.rfind(".");
64 string extension {};
65 if (dotIndex != string::npos) {
66 extension = pathOrDisplayName.substr(dotIndex + 1);
67 CHECK_AND_WARN_LOG(!extension.empty(), "Extension is empty, path/displayName: %{public}s",
68 pathOrDisplayName.c_str());
69 return extension;
70 }
71 }
72
73 MEDIA_ERR_LOG("Failed to obtain file extension because given path/displayName is empty");
74 return "";
75 }
76
77 // Check if the given path is a directory path
IsDirectory(const string & path)78 bool ScannerUtils::IsDirectory(const string &path)
79 {
80 struct stat s;
81
82 if (!path.empty()) {
83 if (stat(path.c_str(), &s) == 0) {
84 if (s.st_mode & S_IFDIR) {
85 return true;
86 }
87 }
88 }
89
90 MEDIA_ERR_LOG("Either path is empty or it is not a directory");
91 return false;
92 }
93
IsRegularFile(const string & path)94 bool ScannerUtils::IsRegularFile(const string &path)
95 {
96 struct stat s;
97 if (!path.empty()) {
98 if (stat(path.c_str(), &s) == 0) {
99 if (s.st_mode & S_IFREG) {
100 return true;
101 }
102 }
103 }
104
105 return false;
106 }
107
108 // Check if the given file starts with '.' , i.e. if it is hidden
IsFileHidden(const string & path)109 bool ScannerUtils::IsFileHidden(const string &path)
110 {
111 if (!path.empty()) {
112 string fileName = GetFileNameFromUri(path);
113 if (!fileName.empty() && fileName.at(0) == '.') {
114 return true;
115 }
116 }
117
118 return false;
119 }
120
121 // Get the parent path
GetParentPath(const string & path)122 string ScannerUtils::GetParentPath(const string &path)
123 {
124 if (!path.empty()) {
125 size_t lastSlashPosition = path.rfind("/");
126 if (lastSlashPosition != string::npos && path.size() > lastSlashPosition) {
127 return path.substr(0, lastSlashPosition);
128 }
129 }
130
131 MEDIA_ERR_LOG("Failed to obtain the parent path");
132 return "";
133 }
134
GetRootMediaDir(string & dir)135 void ScannerUtils::GetRootMediaDir(string &dir)
136 {
137 dir = ROOT_MEDIA_DIR;
138 }
139
GetFileTitle(const string & displayName)140 string ScannerUtils::GetFileTitle(const string &displayName)
141 {
142 string::size_type pos = displayName.find_last_of('.');
143 return (pos == string::npos) ? displayName : displayName.substr(0, pos);
144 }
145
IsDirHidden(const string & path,bool skipPhoto)146 bool ScannerUtils::IsDirHidden(const string &path, bool skipPhoto)
147 {
148 bool dirHid = false;
149
150 if (!path.empty()) {
151 string dirName = ScannerUtils::GetFileNameFromUri(path);
152 if (!dirName.empty() && dirName.at(0) == '.') {
153 MEDIA_DEBUG_LOG("hidden Directory, name:%{private}s path:%{private}s", dirName.c_str(), path.c_str());
154 return true;
155 }
156
157 string curPath = path;
158 string excludePath = curPath.append("/.nomedia");
159 // Check is the folder consist of .nomedia file
160 if (ScannerUtils::IsExists(excludePath)) {
161 return true;
162 }
163
164 // Check is the dir is part of skiplist
165 if (skipPhoto && CheckSkipScanList(path)) {
166 MEDIA_DEBUG_LOG("skip Directory, path:%{private}s", path.c_str());
167 return true;
168 }
169 }
170
171 return dirHid;
172 }
173
IsDirHiddenRecursive(const string & path,bool skipPhoto)174 bool ScannerUtils::IsDirHiddenRecursive(const string &path, bool skipPhoto)
175 {
176 bool dirHid = false;
177 string curPath = path;
178
179 do {
180 dirHid = IsDirHidden(curPath, skipPhoto);
181 if (dirHid) {
182 break;
183 }
184
185 curPath = ScannerUtils::GetParentPath(curPath);
186 if (curPath.empty()) {
187 break;
188 }
189 } while (true);
190
191 return dirHid;
192 }
193
194 // Check if path is part of Skip scan list
CheckSkipScanList(const string & path)195 bool ScannerUtils::CheckSkipScanList(const string &path)
196 {
197 if (path.length() <= ROOT_MEDIA_DIR.length()) {
198 return false;
199 }
200 static const string AUDIO = "Audios";
201 static const string CAMERA = "Camera";
202 static const string Pictures = "Pictures";
203 static const string Videos = "Videos";
204 static const string Doc = "Documents";
205 static const string Download = "Download";
206 // white list
207 static vector<string> list = {
208 { ROOT_MEDIA_DIR + AUDIO },
209 { ROOT_MEDIA_DIR + CAMERA },
210 { ROOT_MEDIA_DIR + Pictures },
211 { ROOT_MEDIA_DIR + Videos },
212 { ROOT_MEDIA_DIR + Doc },
213 { ROOT_MEDIA_DIR + Download },
214 };
215 for (const auto &pathPrefix : list) {
216 if (path.find(pathPrefix) != string::npos) {
217 return false;
218 }
219 }
220 return true;
221 }
222 } // namespace Media
223 } // namespace OHOS
224