#  OpenFiles.pl
#  Example 4.7:
#  ----------------------------------------
#  From "Win32 Perl Scripting: Administrators Handbook" by Dave Roth
#  Published by New Riders Publishing.
#  ISBN # 1-57870-215-1
#
#  This script lists all files that are open on a machine that are opened by
#  remote users.
#
print "From the book 'Win32 Perl Scripting: The Administrator's Handbook' by Dave Roth\n\n";


use vars qw( %Data $PATH $USERS );
use Getopt::Long;
use Win32;
use Win32::Lanman;

%PATH = (
    max     =>  45,
    filler  =>  ' ... ',
);

Configure( \%Config );
if( $Config{help} )
{
    Syntax();
    exit();
}

$USERS = ";" . join( ";", @{$Config{users}} ) . ";";

if( ! scalar @{$Config{servers}} )
{
    push( @{$Config{servers}}, Win32::NodeName() );
}

foreach my $Server ( sort( @{$Config{servers}} ) )
{
    my @FileInfo;
    next if( lc $Server eq $PrevServer );
    $PrevServer = lc $Server;

    print "Open files on \\\\$Server:\n";
    $~ = OUTPUT_HEADER;
    write;
    $~ = OUTPUT;
    $: = "\\-_+";

    foreach my $Path ( @$Config{paths} )
    {
        my( @Info, $User );
        if( Win32::Lanman::NetFileEnum( $Server, $Path, $User, \@Info ) )
        {
            push( @FileInfo, @Info );
        }
    }

    foreach my $File ( @FileInfo )
    {
        undef %Data;
        $Data{path}  = $File->{pathname};
        $Data{user}  = $File->{username};
        $Data{locks} = $File->{num_locks};
        $Data{id}    = $File->{id};

        if( scalar @{$Config{users}} )
        {
            next unless( $USERS =~ /;$Data{user};/i );
        }

        if( ! $Config{full} )
        {
            if( $PATH{max} < length( $Data{path} ) )
            {
                my $PathLength = int( ( $PATH{max} - length( $PATH{filler} ) ) / 2 );
                my $FillerLength = length( $PATH{filler} );
                ( $Data{path} = $File->{pathname} ) =~ s/^(.{$PathLength})(.*?)(.{$PathLength})$/$1$PATH{filler}$3/;
            }
        }
        write;
    }
    print "\n";
}

sub Configure
{
    my( $Config ) = @_;
    my $Result = 0;
    Getopt::Long::Configure( "prefix_pattern=(-|\/)" );
    $Result = GetOptions( $Config, 
                qw(
                    users|u=s@
                    full|f
                    machine|m=s@
                    help|?|h
                ) );
    push( @{$Config->{paths}}, @ARGV );
    foreach my $Machine ( @{$Config->{machine}} )
    {
        if( "*" eq $Machine )
        {
            my $Domain = Win32::DomainName();
            my @List;
            if( Win32::Lanman::NetServerEnum( '', $Domain, SV_TYPE_SERVER, \@List ) )
            {
               map
               {
                   push( @{$Config->{servers}}, $_->{name} );
               } @List;
            }
        }
        else
        {
            push( @{$Config->{servers}}, $Machine );
        }
    }    
    $Config->{help} = 1 unless( $Result );
}

sub Syntax
{
    my( $Script ) = ( $0 =~ /([^\\\/]*?)$/ );
    my( $Line ) = "-" x length( $Script );

    print <<EOT;

$Script
$Line
Display what files are open on a server.

Syntax:
    perl $Script [-f] [-u User] [-m Machine] [Path [$Path2 [...]]]
        -u..........Display only files opened by this user.
                    Use as many -u switches as needed.
        -f..........Display full path of each open file.
        -m..........Examine this machine.
                    Specify * for all machines sharing files.
                    Default is the local machine.
        Path........The path to examine local to the specified server.
                    This can be either a file or a directory path.
                    Default will be ALL files on the server.

EOT

}

format OUTPUT_HEADER=
@<<<<<< @<<<<< @<<<<<<<<<<<<<<<<< @<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
'ID', 'Locks', 'User', 'Path'
------- ------ ------------------ -----------------------------------------
.

format OUTPUT =
@>>>>>> @>>>>> @<<<<<<<<<<<<<<<<< ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
$Data{id}, $Data{locks}, $Data{user}, $Data{path}
~                                 ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                  $Data{path}
~                                 ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                  $Data{path}
~                                 ^<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<
                                  $Data{path}
.
