• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2023 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 "FileInotify"
16 #include "medialibrary_inotify.h"
17 
18 #include <string>
19 #include <thread>
20 
21 #include "unistd.h"
22 #include "media_log.h"
23 #include "media_file_uri.h"
24 #include "medialibrary_bundle_manager.h"
25 #include "medialibrary_object_utils.h"
26 #include "medialibrary_errno.h"
27 #include "medialibrary_data_manager_utils.h"
28 #include "medialibrary_uripermission_operations.h"
29 #include "permission_utils.h"
30 
31 using namespace std;
32 namespace OHOS {
33 namespace Media {
34 std::shared_ptr<MediaLibraryInotify> MediaLibraryInotify::instance_ = nullptr;
35 std::mutex MediaLibraryInotify::mutex_;
36 const int32_t MAX_WATCH_LIST = 200;
37 const int32_t MAX_AGING_WATCH_LIST = 100;
38 
GetInstance()39 shared_ptr<MediaLibraryInotify> MediaLibraryInotify::GetInstance()
40 {
41     if (instance_ != nullptr) {
42         return instance_;
43     }
44     lock_guard<mutex> lock(mutex_);
45     if (instance_ == nullptr) {
46         instance_ = make_shared<MediaLibraryInotify>();
47         if (instance_ == nullptr) {
48             MEDIA_ERR_LOG("GetInstance nullptr");
49             return instance_;
50         }
51         instance_->Init();
52     }
53     return instance_;
54 }
55 
ConvertMediaPath(const std::string & path)56 static string ConvertMediaPath(const std::string &path)
57 {
58     // if input path is /storage/media/local/xxx, convert to /storage/cloud/xxx
59     string mediaPath = path;
60     string localPath = "/storage/media/local/";
61     string cloudPath = "/storage/cloud/";
62     if (mediaPath.find(localPath) != string::npos) {
63         mediaPath.replace(mediaPath.find(localPath), localPath.length(), cloudPath);
64     }
65     return mediaPath;
66 }
67 
WatchCallBack()68 void MediaLibraryInotify::WatchCallBack()
69 {
70     const int32_t READ_LEN = 255;
71     char data[READ_LEN] = {0};
72     while (isWatching_) {
73         int32_t len = read(inotifyFd_, data, READ_LEN);
74         int32_t index = 0;
75         while (index < len) {
76             struct inotify_event *event = reinterpret_cast<struct inotify_event *>(data + index);
77             index += sizeof(struct inotify_event) + event->len;
78             unique_lock<mutex> lock(mutex_);
79             if (watchList_.count(event->wd) == 0) {
80                 continue;
81             }
82             auto &item = watchList_.at(event->wd);
83             auto eventMask = event->mask;
84             auto &meetEvent = item.meetEvent_;
85             meetEvent = (eventMask & IN_MODIFY) ? (meetEvent | IN_MODIFY) : meetEvent;
86             meetEvent = (eventMask & IN_CLOSE_WRITE) ? (meetEvent | IN_CLOSE_WRITE) : meetEvent;
87             meetEvent = (eventMask & IN_CLOSE_NOWRITE) ? (meetEvent | IN_CLOSE_NOWRITE) : meetEvent;
88             if (((meetEvent & IN_CLOSE_WRITE) && (meetEvent & IN_MODIFY)) ||
89                 ((meetEvent & IN_CLOSE_NOWRITE) && (meetEvent & IN_MODIFY))) {
90                 MEDIA_DEBUG_LOG("path:%s, meetEvent:%x file_id:%s", item.path_.c_str(),
91                     meetEvent, item.uri_.c_str());
92                 string id = MediaLibraryDataManagerUtils::GetIdFromUri(item.uri_);
93                 string itemPath = ConvertMediaPath(item.path_);
94                 string bundleName = item.bundleName_;
95                 MediaFileUri itemUri(item.uri_);
96                 MediaLibraryApi itemApi = item.api_;
97                 Remove(event->wd);
98                 lock.unlock();
99                 MediaLibraryObjectUtils::ScanFileAsync(itemPath, id, itemApi);
100                 UriPermissionOperations::DeleteBundlePermission(id, bundleName, itemUri.GetTableName());
101             }
102         }
103     }
104     isWatching_ = false;
105 }
106 
DoAging()107 void MediaLibraryInotify::DoAging()
108 {
109     lock_guard<mutex> lock(mutex_);
110     if (watchList_.size() > MAX_AGING_WATCH_LIST) {
111         MEDIA_DEBUG_LOG("watch list clear");
112         watchList_.clear();
113     }
114 }
115 
DoStop()116 void MediaLibraryInotify::DoStop()
117 {
118     lock_guard<mutex> lock(mutex_);
119     for (auto iter = watchList_.begin(); iter != watchList_.end(); iter++) {
120         if (inotify_rm_watch(inotifyFd_, iter->first) != 0) {
121             MEDIA_ERR_LOG("rm watch fd: %{public}d, fail: %{public}d", iter->first, errno);
122         }
123     }
124     isWatching_ = false;
125     watchList_.clear();
126     inotifyFd_ = 0;
127 }
128 
RemoveByFileUri(const string & uri,MediaLibraryApi api)129 int32_t MediaLibraryInotify::RemoveByFileUri(const string &uri, MediaLibraryApi api)
130 {
131     lock_guard<mutex> lock(mutex_);
132     int32_t wd = -1;
133     for (auto iter = watchList_.begin(); iter != watchList_.end(); iter++) {
134         if (iter->second.uri_ == uri && iter->second.api_ == api) {
135             wd = iter->first;
136             MEDIA_DEBUG_LOG("remove uri:%s wd:%d path:%s",
137                 iter->second.uri_.c_str(), wd, iter->second.path_.c_str());
138             break;
139         }
140     }
141     if (wd < 0) {
142         MEDIA_DEBUG_LOG("remove uri:%s fail", uri.c_str());
143         return E_FAIL;
144     }
145     return Remove(wd);
146 }
147 
Remove(int wd)148 int32_t MediaLibraryInotify::Remove(int wd)
149 {
150     watchList_.erase(wd);
151     if (inotify_rm_watch(inotifyFd_, wd) != 0) {
152         MEDIA_ERR_LOG("rm watch fd:%d fail:%d", wd, errno);
153         return E_FAIL;
154     }
155     return E_SUCCESS;
156 }
157 
Init()158 int32_t MediaLibraryInotify::Init()
159 {
160     if (inotifyFd_ <= 0) {
161         inotifyFd_ = inotify_init();
162         if (inotifyFd_ < 0) {
163             MEDIA_ERR_LOG("add AddWatchList fail");
164             return E_FAIL;
165         }
166     }
167     return E_SUCCESS;
168 }
169 
AddWatchList(const string & path,const string & uri,MediaLibraryApi api)170 int32_t MediaLibraryInotify::AddWatchList(const string &path, const string &uri, MediaLibraryApi api)
171 {
172     lock_guard<mutex> lock(mutex_);
173     if (watchList_.size() > MAX_WATCH_LIST) {
174         MEDIA_ERR_LOG("watch list full, add uri:%s fail", uri.c_str());
175         return E_FAIL;
176     }
177     int32_t wd = inotify_add_watch(inotifyFd_, path.c_str(), IN_CLOSE | IN_MODIFY);
178     if (wd > 0) {
179         string bundleName = MediaLibraryBundleManager::GetInstance()->GetClientBundleName();
180         struct WatchInfo item(path, uri, bundleName, api);
181         watchList_.emplace(wd, item);
182     }
183     if (!isWatching_.load()) {
184         isWatching_ = true;
185         thread(&MediaLibraryInotify::WatchCallBack, this).detach();
186     }
187     return E_SUCCESS;
188 }
189 } // namespace Media
190 } // namespace OHOS