xref: /glogg/src/inotifywatchtowerdriver.cpp (revision c540156c41190af6e419dffb1b2c43c87fdd3cde)
1 #include "inotifywatchtowerdriver.h"
2 
3 INotifyWatchTowerDriver::INotifyWatchTowerDriver() :
4     WatchTowerDriver(), inotify_fd( inotify_init() )
5 {
6 }
7 
8 INotifyWatchTowerDriver::addFile( const std::string& file_name )
9 {
10     // Add a watch for the inode
11     int wd = inotify_add_watch( inotify_fd, file_name.c_str(),
12             IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF );
13 
14     LOG(logDEBUG) << "INotifyWatchTower::addFile new inotify wd " << wd;
15 }
16 
17 INotifyWatchTowerDriver::addSymlink( const std::string& file_name )
18 {
19     symlink_wd = inotify_add_watch( inotify_fd, file_name.c_str(),
20             IN_DONT_FOLLOW | IN_DELETE_SELF | IN_MODIFY | IN_MOVE_SELF );
21     LOG(logDEBUG) << "INotifyWatchTower::addFile new inotify symlink_wd " << symlink_wd;
22     // (not sure a symlink can be modified but you never know)
23 }
24 INotifyWatchTowerDriver::addDir( const std::string& file_name )
25 {
26     inotify_add_watch( inotify_fd, dir->path.c_str(),
27             IN_CREATE | IN_MOVE | IN_ONLYDIR );
28     LOG(logDEBUG) << "INotifyWatchTower::addFile dir " << dir->path
29         << " watched wd " << dir->dir_wd_;
30 }
31 
32 INotifyWatchTowerDriver::removeFile( const INotifyFile& file_id )
33 {
34     /*
35        LOG(logDEBUG) << "INotifyWatchTower::removeNotification removing inotify wd "
36        << file->file_wd_ << " symlink_wd " << file->symlink_wd_;
37        */
38     if ( file->file_wd_ >= 0 )
39         inotify_rm_watch( watch_tower->inotify_fd, file->file_wd_ );
40 }
41 
42 INotifyWatchTowerDriver::removeSymlink( const INotifySymlinkId& symlink_id )
43 {
44     if ( file->symlink_wd_ >= 0 )
45         inotify_rm_watch( watch_tower->inotify_fd, file->symlink_wd_ );
46 }
47 
48 std::vector<ObservedFile*> waitAndProcessEvents( std::shared<> list, std::mutex list_mutex )
49 {
50     fds[0].revents = 0;
51     int poll_ret = poll( fds, 1, 0 );
52 
53     if ( ( poll_ret > 0 ) && ( fds[0].revents & POLLIN ) )
54     {
55         LOG(logDEBUG4) << "Pollin for inotify";
56         char buffer[ INOTIFY_BUFFER_SIZE ]
57             __attribute__ ((aligned(__alignof__(struct inotify_event))));
58 
59         ssize_t nb = read( inotify_fd, buffer, sizeof( buffer ) );
60         if ( nb > 0 )
61         {
62             size_t offset = 0;
63             while ( offset < nb ) {
64                 const inotify_event* event =
65                     reinterpret_cast<const inotify_event*>( buffer + offset );
66 
67                 offset += processINotifyEvent( event );
68             }
69         }
70         else
71         {
72             LOG(logWARNING) << "Error reading from inotify " << errno;
73         }
74     }
75 
76     // Treats the passed event and returns the number of bytes used
77     size_t INotifyWatchTower::processINotifyEvent( const struct inotify_event* event )
78     {
79         LOG(logDEBUG) << "Event received: " << std::hex << event->mask;
80 
81         std::unique_lock<std::mutex> lock( observers_mutex_ );
82 
83         ObservedFile* file = nullptr;
84 
85         if ( event->mask & ( IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF ) )
86         {
87             LOG(logDEBUG) << "IN_MODIFY | IN_DELETE_SELF | IN_MOVE_SELF for wd " << event->wd;
88 
89             // Retrieve the file
90             file = observed_file_list_.searchByFileOrSymlinkWd( event->wd );
91         }
92         else if ( event->mask & ( IN_CREATE | IN_MOVED_TO | IN_MOVED_FROM ) )
93         {
94             LOG(logDEBUG) << "IN_CREATE | IN_MOVED_TO | IN_MOVED_FROM for wd " << event->wd
95                 << " name: " << event->name;
96 
97             // Retrieve the file
98             file = observed_file_list_.searchByDirWdAndName( event->wd, event->name );
99 
100             if ( file )
101             {
102                 LOG(logDEBUG) << "Dir change for watched file " << event->name;
103             }
104         }
105         else
106         {
107             LOG(logDEBUG) << "Unexpected event: " << event->mask << " wd " << event->wd;
108         }
109 
110         // Call all our observers
111         if ( file )
112         {
113             for ( auto observer: file->callbacks )
114             {
115                 // Here we have to cast our generic pointer back to
116                 // the function pointer in order to perform the call
117                 const std::shared_ptr<std::function<void()>> fptr =
118                     std::static_pointer_cast<std::function<void()>>( observer );
119                 // The observer is called with the mutex held,
120                 // Let's hope it doesn't do anything too funky.
121                 (*fptr)();
122             }
123         }
124 
125         return sizeof( struct inotify_event ) + event->len;
126     }
127