Add to enable TIZEN_ASAN_ACTIVATION
[platform/core/appfw/launchpad.git] / src / launchpad-process-pool / file_monitor.cc
1 /*
2  * Copyright (c) 2023 Samsung Electronics Co., Ltd All Rights Reserved
3  *
4  * Licensed under the Apache License, Version 2.0 (the License);
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an AS IS BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 #include "launchpad-process-pool/file_monitor.hh"
18
19 #include "lib/common/inc/launchpad_common.h"
20
21 namespace launchpad {
22
23 namespace fs = std::filesystem;
24
25 gboolean FileMonitor::OnEventReceived(GIOChannel* channel,
26                                      GIOCondition cond,
27                                      gpointer user_data) {
28   char buf[4096] __attribute__((aligned(__alignof__(struct inotify_event))));
29   char* ptr;
30   ssize_t len;
31   struct inotify_event* event;
32   auto event_listener = reinterpret_cast<FileMonitor*>(user_data);
33   int fd = g_io_channel_unix_get_fd(channel);
34
35   while ((len = read(fd, buf, sizeof(buf))) > 0) {
36     for (ptr = buf; ptr < buf + len;
37          ptr += sizeof(struct inotify_event) + event->len) {
38       event = reinterpret_cast<struct inotify_event*>(ptr);
39       char* nptr = ptr + sizeof(struct inotify_event) + event->len;
40       if (nptr > buf + len)
41         break;
42
43       if (!event->len || event_listener->file_name_ != event->name)
44         continue;
45
46       if (event->mask & IN_CREATE) {
47         if (event_listener->listener_)
48           event_listener->listener_->OnFileChanged(FileMonitorEvent::Created);
49       } else if (event->mask & IN_MODIFY) {
50         if (event_listener->listener_)
51           event_listener->listener_->OnFileChanged(FileMonitorEvent::Modified);
52       } else if (event->mask & IN_DELETE) {
53         if (event_listener->listener_)
54           event_listener->listener_->OnFileChanged(FileMonitorEvent::Deleted);
55       }
56
57       return G_SOURCE_CONTINUE;
58     }
59   }
60
61   return G_SOURCE_CONTINUE;
62 }
63
64 FileMonitor::FileMonitor(const std::string_view file_path,
65                          FileMonitor::IEvent* listener)
66     : listener_(listener) {
67   fs::path path(file_path);
68   parent_path_ = path.parent_path();
69   file_name_ = path.filename();
70   if (!fs::exists(parent_path_)) {
71     if (!fs::create_directories(parent_path_)) {
72       _E("Failed to create directory. %s", parent_path_.c_str());
73       return;
74     }
75   }
76
77   if (fs::exists(path)) {
78     if (listener_)
79       listener_->OnFileChanged(FileMonitor::FileMonitorEvent::Created);
80   }
81
82   fd_ = inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
83   if (fd_ == -1) {
84     int ret = errno;
85     _E("Failed to inotify_init. errno: %d", ret);
86     disposed_ = true;
87     return;
88   }
89
90   wd_ = inotify_add_watch(fd_, parent_path_.c_str(),
91                           IN_CREATE | IN_MODIFY | IN_DELETE);
92   if (wd_ == -1) {
93     int ret = errno;
94     _E("Failed to inotify_add_watch. errno: %d", ret);
95     Dispose();
96     return;
97   }
98
99   channel_ = g_io_channel_unix_new(fd_);
100   if (channel_ == nullptr) {
101     _E("Failed to create GIO channel");
102     Dispose();
103     return;
104   }
105
106   g_io_channel_set_close_on_unref(channel_, false);
107   tag_ = g_io_add_watch(channel_, G_IO_IN, OnEventReceived, this);
108   if (tag_ == 0) {
109     _E("Failed to add watch");
110     Dispose();
111     return;
112   }
113
114   disposed_ = false;
115 }
116
117 FileMonitor::~FileMonitor() {
118   Dispose();
119 }
120
121 void FileMonitor::Dispose() {
122   if (disposed_)
123     return;
124
125   if (tag_) {
126     g_source_remove(tag_);
127     tag_ = 0;
128   }
129
130   if (channel_ != nullptr) {
131     g_io_channel_unref(channel_);
132     channel_ = nullptr;
133   }
134
135   if (wd_ > 0) {
136     inotify_rm_watch(fd_, wd_);
137     wd_ = 0;
138   }
139
140   if (fd_ > 0) {
141     close(fd_);
142     fd_ = 0;
143   }
144
145   disposed_ = true;
146 }
147
148 }  // namespace launchpad