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