++ed by:

3 PAUSE users
2 non-PAUSE users.

Author image Daniel Pfeiffer


Mpp::File -- cached information about files and directories


Note that we show both a functional and an object oriented syntax here. Since the latter has a measurable overhead, and as this module is very heavily used, the functional syntax is to be preferred.

  use Mpp::File;
  chdir($new_dir);              # Changes to new directory and keeps track
                                # of the directory name in the variable
                                # $CWD_INFO.
  $finfo = file_info('filename');

  build_handle( $finfo );
  $finfo->build_handle;         # Returns the handle for the process that is
                                # building (or has built) the file.
  $finfo->set_build_handle($handle); # Sets the handle for the process
                                # that's currently building the file.

  $build_rule = build_rule( $finfo ); # Returns the rule for building the file,
                                # if such a rule exists.
  $finfo->set_build_rule($rule); # Set the rule used to build this file.

                                # Returns a piece of information from the build
                                # info file, if there is one.
  set_build_info_string($finfo, 'key', 'value');
  $finfo->set_build_info_string('key', 'value');
  Mpp::File::update_build_infos(); # Flushes build info cache to disk.

  if (exists_or_can_be_built( $finfo )) {}
  if ($finfo->exists_or_can_be_built) {}
  my $dir_finfo = parent( $finfo );
  my $dir_finfo = $finfo->parent; # The directory containing this file.
  $name = absolute_filename( $finfo );
  $name = $finfo->absolute_filename;    # Returns absolute file name.
                                # If more than one name can be used
                                # (because of soft links), the shortest
                                # possible one is used to avoid problems with
                                # the automounter.
  $name = relative_filename( $finfo );
  $name = $finfo->relative_filename;
  $relative_fname = relative_filename( $finfo, 'dir');
  $relative_fname = $finfo->relative_filename('dir');
  $relative_fname = relative_filename($finfo, $dirinfo);
  $relative_fname = $finfo->relative_filename($dirinfo);
                                # Returns name relative to given directory.

  may_have_changed( $finfo );
  $finfo->may_have_changed;     # Indicate that the file may have changed on
                                # disk, so invalidate (or check) cached info.

  if (file_exists( $finfo )) { ... }
  if ($finfo->file_exists) { ... }
  $date = file_mtime( $finfo );
  $date = $finfo->file_mtime;

  if (is_dir( $finfo )) { ... }
  if ($finfo->is_dir) { ... }
  if (is_writable( $finfo )) { ... }
  if ($finfo->is_writable) { ... }
  if (is_symbolic_link( $finfo )) { ... }
  if ($finfo->is_symbolic_link) { ... }

  Mpp::File::unlink( $finfo );
  $finfo->unlink;               # Deletes the file.

  my $link_finfo = dereference( $finfo );
  my $link_finfo = $finfo->dereference;
                                # Dereference a symbolic link.

  read_directory( $finfo );
  $finfo->read_directory;       # Try to (re)read the contents of a directory.

  my $stat_array = stat_array( $finfo ); # Return the array returned by stat().
  my $stat_array = $finfo->stat_array; # Return the array returned by stat().
  my $lstat_array = lstat_array( $finfo ); # Return the array returned by lstat().
  my $lstat_array = $finfo->lstat_array; # Return the array returned by lstat().
  relative_filename('file', 'dir'); # Returns relative name of file
                                # with respect to the directory.


Mpp::File is an efficient way to avoid re-statting files and rereading directories. For each known file, there is a Mpp::File structure that describes what is known about the file. You may add arbitrary additional information to the structure.

Mpp::File is designed so it won't be confused by soft-linked directories. However, it will have problems if a soft link initially points to one directory and then is changed to point to a different directory, or if files are referred to through a symbolic link to a directory before the symbolic link is actually created. Generally speaking, it's not a good idea to modify existing soft links.

Mpp::File can be used alone. Some supplemental routines useful only in the context of makepp are found in Mpp/FileOpt.pm, and in fact that file overrides some of the routines here.


We only store the subset of (l)stat values which makepp needs. This reduces makepp's memory footprint by 1.5% and execution time by 4% compared to the 13-element array.


True if we think makepp should treat filenames as case sensitive.

At present, makepp can be either 100% case insensitive, converting all filenames to lower case, or 100% case sensitive. Makepp currently cannot handle some files coming from a case-insensitive file system and other files coming from a case-sensitive file system.

This routine is just a guess. We look at the current directory to see if it looks case sensitive, and switch makepp into the appropriate mode.


On Windows this is true if you can't stat 'xyz', when only 'xyz.exe' exists. That is ActiveState at least until 5.10.0 and possibly older Cygwin versions.


  $str = absolute_filename( $fileinfo );

Returns the absolute file name.

chdir('new dir')

  chdir('new dir')

Changes to the indicated directory, and keeps track of the change in the variable $CWD_INFO. Dies with a message if the chdir failed.

You can pass a Mpp::File structure describing the directory instead of the directory name itself if that is more convenient.

This subroutine is automatically exported into any packages that use Mpp::File, so your chdirs will work automatically.


  $finfo = dereference( $fileinfo );

If the file is a symbolic link, this returns a Mpp::File structure for the file it points to. If the symbolic link points to another symbolic link, returns what that link points to. If the file is not a symbolic link, returns the original Mpp::File structure.


  if (file_exists( $file_info )) { ... }

Returns true (actually, returns the Mpp::File structure) if the file exists, and undef if it doesn't.


  $finfo = file_info('filename');
  $finfo = file_info('filename', $dirinfo);

Returns the Mpp::File structure for the given file. If no Mpp::File structure exists, creates a new one for it.

The optional second argument specifies a directory the file name should be relative to. By default, this is the current directory.

  foreach (@{dir_contents( $finfo )}) {
    exists_or_can_be_built( $_, 0 ) or next;    # Skip if file doesn't exist.
                                # (Files which don't exist can have Mpp::File
                                # entries, if you happened to call
                                # file_info on them explicitly.)
    # do your thing here.

If you want to iterate through all the files which are in a directory, not just the ones encountered previously, then call $dirinfo->read_directory before using the above code snippet.


Does the work of file_info when filename contains directory separators. You can call this explicitly in places where filename is (almost) sure to have directory separators.


  $date = file_mtime( $file_info );
  $date = file_mtime('filename');

Returns the last modification time for the given file. If the file is a symbolic link, this returns the modification for the file the link refers to. Return undef if it doesn't exist.


  if (is_dir( $fileinfo )) { ... }

Returns true (actually, returns the fileinfo structure) if the given file is actually a directory. Does not return true for soft links that point to directories. (If you want to do that, you can call is_symbolic_link and then follow the symbolic link using dereference.) See under file_info for how to examine the contents of the directory.

is_dir() only returns true for directories that currently exist. You can create Mpp::File structures for directories that don't exist yet; to check for this kind of directory, use is_or_will_be_dir().


  if (is_or_will_be_dir( $fileinfo )) { ... }

Returns true (actually, returns the fileinfo structure) if the given file is actually a directory, or if it will be a directory (because file_info() was called using it as a directory). Also returns true for soft links that point to directories.


  if (is_readable( $finfo )) { ... }

Returns true if the given file or directory can be read.


  if (have_read_permission( $finfo )) { ... }

Returns true if the given file or directory has its read permission set for the effective user ID. This is not the same as is_readable, because there are other reasons that you might not be able to read the file.

  if (is_symbolic_link( $finfo )) { ... }

Returns true (actually, returns the Mpp::File structure) if the given file is a symbolic link.


  if (is_writable( $dirinfo )) { ... }

Returns true if the given directory can be written to. Because of the complexity of testing for permission, we test by actually trying to write a file to that directory.


   if (is_writable_user( $finfo ))

Determines if a given file is writable by its owner by just checking the mode bits. This does not test whether the current user is the owner.


A static method with no arguments. Call this to notify this package that some code has been run that might have changed something (especially in the case of adding files) that we might care about without updating the database.


   $statinfo = stat_array( $fileinfo );
   $uid = $statinfo->[STAT_SIZE];       # Or whatever field you're interested in.

Returns the array of values returned by the lstat function on the file. The values are cached, so calling this repeatedly entails only minimal extra overhead.


  may_have_changed( $finfo );

Indicates that a file may have changed, so that any cached values (such as the signature or the file time) are invalid.


  check_for_change( $finfo );

Like may_have_changed, indicates that a file may have changed, but retains the build info unless the signature actually changed. This is used in place of may_have_changed in order to prevent the unnecessary destruction of build info, which is expensive to compute in some cases.


   Mpp::File::mkdir( $dirinfo );

Unless it exists, makes the directory specified by the Mpp::File structure (and any parent directories that are necessary).


   $dirinfo = parent( $finfo );

Returns the directory containing the file.


  read_directory( $dirinfo );

Rereads the given directory so we know what files are actually in it.


  $str = relative_filename( $fileinfo ); # Relative to current directory.
  $str = relative_filename( $fileinfo, $dirinfo);
  $n = relative_filename( $fileinfo, $dirinfo, $distance ); # Only count hops.

Return a file name relative to the given directory, if specified. If a directory is specified, which was not previously known to be a directory (e.g. because it is yet to be created and no files therein have been mentioned yet) it becomes marked as directory. If no directory is specified, uses the current working directory. If the directory and the file have no directories but the topmost in common (e.g., like '/home/mystuff/stuff' and '/usr/local/bin'), then an absolute file name is returned.

A 3rd arg means to measure the distance to a file in directory traversals. In the case where otherwise an absolute path would be returned, 999 is added to the length to make it further than any relative path.


   $statinfo = stat_array( $fileinfo );
   $statinfo = stat_array('filename');
   $uid = $statinfo->[STAT_SIZE];       # Or whatever field you're interested in.

Returns the array of values returned by the stat function on the file. The values are cached, so calling this repeatedly entails only minimal extra overhead.

If the file is a symbolic link, this returns the stat values for the file the link refers to.


Similar to stat_array, except that you need to call this instead if it's a directory and you need to get accurate timestamps or link counts.

   Mpp::File::unlink( $fileinfo );

Removes the file and marks it in the cache as non-existent.


Gary Holt (holt@lnc.usc.edu)