Lhamo Latso has asked for the wisdom of the Perl Monks concerning the following question:

Dear Monk, I've been away for awhile and my scoping skills are getting weak. Could I get some pointers on why I get the wrong directory size total on the code below? I wish to add up all the file sizes below my dad root.

package MyApache::SF_Upload; ... use vars qw($UPLOAD_DIR $dir_size); sub handler { ... # Check that the directory is not getting full. $dir_size = 0; my $dirsz = dir_size( $UPLOAD_DIR ."/$dad" ); if ( $dirsz > MAX_DIR_SIZE ) { $apr->log_error("Upload directory is nearly full, $dirsz" ); return 507; # HTTP_INSUFFICIENT_STORAGE } $apr->warn("Upload directory is nearly full, $dirsz" ); ... } sub dir_size { my $dir = shift; # Loop through files and sum the sizes; this will descend down sub +dirs opendir DIR, $dir or die "Unable to open $dir: $!"; while ( $_ = readdir DIR ) { stat("$dir/$_"); if (-d _ ) { $dir_size += dir_size("$dir/$_") unless ($_ eq "." || $_ eq ".."); } else { $dir_size += -s _ ; } warn("DIR filename: $dir/$_ at $dir_size"); } return $dir_size; }

Everything goes along fine, printing the warn messages to the log, then we hit the one and only subdirectory. It descends fine, accumulating the sizes into $dir_size and printing the warn messages, too.

Then, I get completely out of the dir_size sub, with a warn message of exactly double the bytes of the last directory warn message. Nothing is printed in between, and the total is missing quite a few files. I think it hit the return and exited both of the recursive paths.

Could it be the perl version that was shipped with Oracle Apache? (5.6.1) The OS is RedHat AS v2.1 2.4.9-e.27smp. This is a modperl program, if that matters.

Replies are listed 'Best First'.
Re: Recursive tree walk with scoping issues
by Zaxo (Archbishop) on Oct 01, 2003 at 01:35 UTC

    This is a classic error with global filehandles. Your recursive routine dir_size() opens the DIR handle at each level it's called. That closes the previous opening of it, invalidating the handle after the inner call returns. You can repair that in line 22 with,

    opendir local(*DIR), $dir or die "Unable to open $dir: $!"; # or # opendir my $dh, $dir or die "Unable to open $dir: $!";
    respelling the handle name everywhere in the lexical version.

    After Compline,
    Zaxo

Re: Recursive tree walk with scoping issues
by dws (Chancellor) on Oct 01, 2003 at 06:08 UTC
    In addition to the scoping issue with file handles that Zaxo caught, you have a runaway scoping problem with $_.

    Instead of letting it change out from under you as you recurse, try writing

    while ( my $file = readdir DIR ) { ...
    and eliminate your use of $_ altogether.