• 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 #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 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
GetFileExtension(const string & path)62 string ScannerUtils::GetFileExtension(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 
75 // Check if the given path is a directory path
IsDirectory(const string & path)76 bool ScannerUtils::IsDirectory(const string &path)
77 {
78     struct stat s;
79 
80     if (!path.empty()) {
81         if (stat(path.c_str(), &s) == 0) {
82             if (s.st_mode & S_IFDIR) {
83                 return true;
84             }
85         }
86     }
87 
88     MEDIA_ERR_LOG("Either path is empty or it is not a directory");
89     return false;
90 }
91 
IsRegularFile(const string & path)92 bool ScannerUtils::IsRegularFile(const string &path)
93 {
94     struct stat s;
95     if (!path.empty()) {
96         if (stat(path.c_str(), &s) == 0) {
97             if (s.st_mode & S_IFREG) {
98                 return true;
99             }
100         }
101     }
102 
103     return false;
104 }
105 
106 // Check if the given file starts with '.' , i.e. if it is hidden
IsFileHidden(const string & path)107 bool ScannerUtils::IsFileHidden(const string &path)
108 {
109     if (!path.empty()) {
110         string fileName = GetFileNameFromUri(path);
111         if (!fileName.empty() && fileName.at(0) == '.') {
112             return true;
113         }
114     }
115 
116     return false;
117 }
118 
119 // Get the parent path
GetParentPath(const string & path)120 string ScannerUtils::GetParentPath(const string &path)
121 {
122     if (!path.empty()) {
123         size_t lastSlashPosition = path.rfind("/");
124         if (lastSlashPosition != string::npos && path.size() > lastSlashPosition) {
125             return path.substr(0, lastSlashPosition);
126         }
127     }
128 
129     MEDIA_ERR_LOG("Failed to obtain the parent path");
130     return "";
131 }
132 
GetRootMediaDir(string & dir)133 void ScannerUtils::GetRootMediaDir(string &dir)
134 {
135     dir = ROOT_MEDIA_DIR;
136 }
137 
GetFileTitle(const string & displayName)138 string ScannerUtils::GetFileTitle(const string &displayName)
139 {
140     string::size_type pos = displayName.find_last_of('.');
141     return (pos == string::npos) ? displayName : displayName.substr(0, pos);
142 }
143 
IsDirHidden(const string & path)144 bool ScannerUtils::IsDirHidden(const string &path)
145 {
146     bool dirHid = false;
147 
148     if (!path.empty()) {
149         string dirName = ScannerUtils::GetFileNameFromUri(path);
150         if (!dirName.empty() && dirName.at(0) == '.') {
151             MEDIA_DEBUG_LOG("hidden Directory, name:%{private}s path:%{private}s", dirName.c_str(), path.c_str());
152             return true;
153         }
154 
155         string curPath = path;
156         string excludePath = curPath.append("/.nomedia");
157         // Check is the folder consist of .nomedia file
158         if (ScannerUtils::IsExists(excludePath)) {
159             return true;
160         }
161 
162         // Check is the dir is part of skiplist
163         if (CheckSkipScanList(path)) {
164             MEDIA_DEBUG_LOG("skip Directory, path:%{private}s", path.c_str());
165             return true;
166         }
167     }
168 
169     return dirHid;
170 }
171 
IsDirHiddenRecursive(const string & path)172 bool ScannerUtils::IsDirHiddenRecursive(const string &path)
173 {
174     bool dirHid = false;
175     string curPath = path;
176 
177     do {
178         dirHid = IsDirHidden(curPath);
179         if (dirHid) {
180             break;
181         }
182 
183         curPath = ScannerUtils::GetParentPath(curPath);
184         if (curPath.empty()) {
185             break;
186         }
187     } while (true);
188 
189     return dirHid;
190 }
191 
192 // Initialize the skip list
InitSkipList()193 void ScannerUtils::InitSkipList()
194 {
195     hash<string> hashStr;
196     size_t hashPath;
197     string path;
198 
199     /*
200      * 1. file path: in disk or hard code? path?
201      * 2. call_once: no need to init again if it is really empty
202      * 3. add lock
203      */
204     ifstream skipFile(SKIPLIST_FILE_PATH.c_str());
205     if (skipFile.is_open()) {
206         while (getline(skipFile, path)) {
207             hashPath = hashStr(path);
208             skipList_.insert(skipList_.begin(), hashPath);
209         }
210         skipFile.close();
211     }
212 
213     return;
214 }
215 
216 // Check if path is part of Skip scan list
CheckSkipScanList(const string & path)217 bool ScannerUtils::CheckSkipScanList(const string &path)
218 {
219     hash<string> hashStr;
220     size_t hashPath;
221 
222     vector<string> list = {
223         { ROOT_MEDIA_DIR + AUDIO_BUCKET },
224         { ROOT_MEDIA_DIR + PHOTO_BUCKET },
225     };
226     // only skip path as "/storage/cloud/files/Photo" when scanDir
227     // doesn't work in scanFile as path likes "/storage/cloud/files/Photo/*"
228     if (find(list.begin(), list.end(), path) != list.end()) {
229         return true;
230     }
231     if (skipList_.empty()) {
232         InitSkipList();
233     }
234 
235     hashPath = hashStr(path);
236     if (find(skipList_.begin(), skipList_.end(), hashPath) != skipList_.end()) {
237         return true;
238     }
239     return false;
240 }
241 } // namespace Media
242 } // namespace OHOS
243