From: [EMAIL PROTECTED] > Charlie Farinella <[EMAIL PROTECTED]> writes: > > > On Wednesday 16 January 2008, Peter Scott wrote: > >> On Tue, 15 Jan 2008 15:13:29 -0500, Charlie Farinella wrote: > >> > I need to monitor a directory and when a file is created, modify it. > >> > I've been playing with Linux::Inotify2 and may be able to make that > >> > work, but am wondering if this is something that people do > > routinely. > >> > > >> > My search at CPAN wasn't particularly fruitful. > >> > >> Did you see File::Monitor? > >> > > > > I didn't, but it looks good, thank you. I actually have something > > working using Linux::Inotify2. I'll play with this one and see which > > one works better for me. > > > > thanks again. > > Charlie, > Have you encountered having to do this on MS-windows OS? If you have > can you tell a little about how to set it up? > > I spent most of a day trying to find something that will notice when > files are created but recursively. I found vbs scripts that I know > nothing about but only one directory [no recusion], but wondered if > perl can do it on the MS-windows OS. > > I expected there to be lots of good tools since it would seem kind of > natural for security oriented software to be able to notice file > creation.
Most often you make things so that you do not have to monitor whole directory trees. In either case the OS only let's you watch directories, not whole branches. What is does let you do is to watch several directories at once. So all you have to do is to find all directories in the branch and say that you want to watch them all. And whenever a directory is created add it to the list. I use use Win32::IPC qw(wait_any); use Win32::ChangeNotify; ... sub PrepareNotifies { undef @notify; undef @path; undef %init_dirs; foreach my $section (keys %$config) { next if $section =~ /^[:#;']/; my $path = $config->{$section}->{searchPath}; $config->{$section}->{ignoreDirsRE} = mask2re( $config->{$section}- >{ignoreDirs}) if $config->{$section}->{ignoreDirs} ne ''; $init_dirs{$path} = 1; $pipe->WriteLn("set\0$path\0$section"); PrepareSubdirs($section, $path, ''); } my $notify; foreach my $path (keys %init_dirs) { $notify = Win32::ChangeNotify->new($path,0,"LAST_WRITE FILE_NAME") or LogNT(qq{Can't create Win32::ChangeNotify object(}.(scalar(@notify)+1).qq{) for $path: $^E\n}) and next; push @notify, $notify; push @path, $path; $pipe->WriteLn(join("\0", 'scan', $path, Win32::GetTickCount())); } LogNT("No valid projects in the INI file!") unless @notify; } sub PrepareSubdirs { my ($section, $path, $root) = @_; chdir $path or return; opendir my $DIR, '.' or return; while (defined(my $subdir = readdir $DIR)) { next if $subdir =~ /^\.\.?$/; next unless -d $subdir; $subdir = lc $subdir; if (exists $config->{$section}->{ignoreDirsRE} and "$root$subdir" =~ $config->{$section}->{ignoreDirsRE}) { LogNT("Directory $root$subdir is ignored by project [$section]"); next; } my $subpath = "$path\\$subdir"; $init_dirs{$subpath} = 1; $pipe->WriteLn("set\0$subpath\0$section"); PrepareSubdirs($section, $subpath, "$root$subdir\\"); chdir $path; # chdir back } closedir $DIR; } PrepareNotifies(); # looooooop my $loopcount = -1; my $tickcount = 1; sub doLoop { while (1) { DoEvents(1, 1, sub { # DoEvents( sub {$pipe->WriteLn("pause")}, 1, sub { Log("Asking worker to quit. This may take some time, the worker will finish pending commands first!"); $pipe->WriteLn('quit'); if (! $sem->wait(30*1000)) { # 30 seconds Log("Worked doesn't respond! Quiting anyway."); } 1; }); my $pathnum; if (@notify == 0) { #LogNT("# No dirs to watch!") if DEBUG; sleep(1); $pathnum = 0; } elsif (@notify <= 64) { #LogNT("# Bellow 64 dirs :-)") if DEBUG; $pathnum = wait_any(@notify, 1000); # once a second #LogNT("# wait_any() returned $pathnum") if DEBUG; } else { #LogNT("# Above 64 dirs :-(") if DEBUG; # wait_any accepts only at most 64 objects! my $chunkcount = int((@notify+63)/64); # ceil(@notify/64) my @ary; for my $chunk (0..$chunkcount-2) { @ary = @notify[$chunk*64 .. ($chunk*64+63)]; $pathnum = wait_any(@ary, 0); Log("Can't monitor a directory: $^E") unless defined $pathnum; if ($pathnum > 0) { $pathnum+=($chunk*64); last; } } if ($pathnum == 0) { @ary = @notify[($chunkcount-1)*64 .. $#notify]; $pathnum = wait_any(@ary, 1000); Log("Can't monitor a directory: $^E\n") unless defined $pathnum; if ($pathnum > 0) { $pathnum+=(($chunkcount-1)*64); } } } #LogNT("# wait_any() returned $pathnum") if DEBUG; if ($pathnum == 0) { # timeout if ($INIFile_age != (stat(INIFILE))[9]) { $INIFile_age = (stat(INIFILE))[9]; Log "INI file changed!"; ReadConfig(); $pipe->Write("readINI\n"); PrepareNotifies(); } $pipe->WriteLn("checkTrans") if ($loopcount = ($loopcount + 1) % (INTERVAL * 60)) == 0; LogNT('tick: '.Win32::Daemon::Simple::Now()) if TICK and ($tickcount = ($tickcount + 1) % 60) == 0; next; } $tickcount = 1 if TICK; if ($pathnum < 0) { Log "Abandoned mutex $path[-$pathnum-2]"; last; } $pathnum--; # we need it zero based eval { $pipe->WriteLn(join("\0", 'scan', $path[$pathnum], Win32::GetTickCount())); $notify[$pathnum]->reset; }; if ($@) { Log("ERROR caught in watcher: $@"); sleep(1); } } # of while(1) } while (1) { eval { doLoop; }; if ($@) { Log("ERROR caught in watcher: $@"); } } within a service (daemon if you want, I'm using Win32::Daemon::Simple for that). The code above includes processing data from the INI file and sends notifications to another process whenever it detects a change, but I think it might still be of help. Please notice though that you can't watch more than 64 directories in one call to wait_any() so you have to wait for the directories in "chunks". I did not find another way around that. Hope this is of any use, Jenda ===== [EMAIL PROTECTED] === http://Jenda.Krynicky.cz ===== When it comes to wine, women and song, wizards are allowed to get drunk and croon as much as they like. -- Terry Pratchett in Sourcery -- To unsubscribe, e-mail: [EMAIL PROTECTED] For additional commands, e-mail: [EMAIL PROTECTED] http://learn.perl.org/