NAME

File::System::Object - Abstract class that every file system module builds upon

DESCRIPTION

Before reading this documentation, you should see File::System.

File system modules extend this class to provide their functionality. A file system object represents a path in the file system and provides methods to locate other file system objects either relative to this object or from an absolute root.

If you wish to write your own file system module, see the documentation below for "MODULE AUTHORS".

FEATURES

The basic idea is that every file system is comprised of objects. In general, all file systems will contain files and directories. Files are object which contain binary or textual data, while directories merely contain more files. Because any given file system might have arbitrarily many (or few) different types and the types might not always fall into the "file" or "directory" categories, the File::System::Object attempts to generalize this functionality into "content" and "container".

More advanced types might also be possible, e.g. symbolic links, devices, FIFOs, etc. However, at this time, no general solution is provided for handling these. (Individual file system modules may choose to add support for these in whatever way seems appropriate.)

Each file system object must specify a method stating whether it contains file content and another method stating whether it may contain child files. It is possible that a given file system implementation provides both simultaneously in a single object.

All file system objects allow for the lookup of other file system object by relative or absolute path names.

PATH METHODS

These methods provide the most generalized functionality provided by all objects. Each path specified to each of these must follow the rules given by the "FILE SYSTEM PATHS" section and may either be relative or absolute. If absolute, the operation performed will be based around the file system root. If relative, the operation performed depends on whether the object is a container or not. If a container, paths are considered relative to this object. If not a container, paths are considered relative to the parent of the current object.

$root = $obj->root

Return an object for the root file system.

$test = $obj->exists($path)

Check the given path $path and determine whether a file system object exists at that path. Return a true value if there is such an object or false otherwise. If $path is undefined, the method should assume $obj->path.

$file = $obj->lookup($path)

Lookup the given path $path and return a File::System::Object reference for that path or undef.

@objs = $obj->glob($glob)

Find all files matching the given file globs $glob. The glob should be a typical csh-style file glob---see "FILE SYSTEM PATHS" below. Returns all matching objects. Note that globs are matched against '.' and '..', so care must be taken in crafting a glob that hopes to match files starting with '.'. (The typical solution to match all files starting with '.' is '.??*' under the assumption that one letter names are exceedingly rare and to be avoided, by the same logic.)

@files = $obj->find($want, @paths)

This is similar in function to, but very different in implementation from File::Find.

Find all files matching or within the given paths @paths or any subdirectory of those paths, which pass the criteria specifed by the $want subroutine. If no @paths are given, then "$obj" is considered to be the path to search within.

The $want subroutine will be called once for every file found under the give paths. The $want subroutine may expect a single argument, the File::System::Object representing the given file. The $want subroutine should return true to add the file to the returned list or false to leave the file out. The $want subroutine may also set the value of $File::System::prune to a true value in order to cause all contained child object to be skipped from search.

The implementation should perform a depth first search so that children are checked immediately after their parent (unless the children are pruned, of course).

$test = $obj->is_creatable($path, $type)

Returns true if the user can use the create method to create an object at $path.

$new_obj = $obj->create($path, $type)

Attempts to create the object at the given path, $path with type $type. Type is a string containing one or more case-sensitive characters describing the type. Here are the meanings of the possible characters:

d

Create a container (named "d" for "directory"). This can be used alone or with the "f" flag.

f

Create a content object (named "f" for "file"). This can be used alone or with the "d" flag.

The is_creatable method may be used first to determine if the operation is possible.

METADATA METHODS

These are the general methods that every File::System::Object will provide.

"$obj"

The stringify operator is overloaded so that if this value is treated as a string it will take on the value of the "path" property.

$name = $obj->is_valid

This method returns whether or not the object is still valid (i.e., the object it refers to still exists).

$name = $obj->basename

This is the base name of the object (local name with the rest of the path stripped out). This value is also available as $obj->get_property('basename'). Note that the root object basename should be '/'. This fits better with unix, but actually differs from how Perl normally works.

$path = $obj->dirname

This the absolute canonical path up to but not including the base name. If the object represents the root path of the file system (i.e., .. = .), then it is possible that basename = dirname = path. This value is also available as $obj->get_property('dirname').

$path = $obj->path

This is the absolute canonical path to the object. This value is also available as $obj->get_property('path').

$test = $obj->is_root

Returns true if this file system object represents the file system root.

$parent_obj = $obj->parent

This is equivalent to:

$parent_obj = $obj->lookup($obj->dirname);

of you can think of it as:

$parent_obj = $obj->lookup('..');

This will return the file system object for the container. It will return itself if this is the root container.

@keys = $obj->properties

Files may have an arbitrary set of properties associated with them. This method merely returns all the possible keys into the get_property method.

@keys = $obj->settable_properties

The keys returned by this method should be a subset of the keys returned by properties. These are the modules upon which it is legal to call the set_property method.

$value = $obj->get_property($key)

Files may have an arbitrary set of properties associated with them. Many of the common accessors are just shortcuts to calling this method.

In every implementation it must return values for at least the following keys:

basename

See basename for a description. When implementing this, you may wish to use the basename_of_path helper.

dirname

See dirname for a description. When implementing this, you may wish to use the dirname_of_path helper.

object_type

See object_type for a description.

path

See path for a description.

$obj->set_property($key, $value)

This sets the property given by $key to the value in $value. This should fail if the given key is not found in $key.

$obj->rename($name)

Renames the name of the file to the new name. This method cannot be used to move the file to a different location. See move for that.

$obj->move($to, $force)

Moves the file to the given path. After running, this object should refer to the file in it's new location. The $to argument must be a reference to the file system container (from the same file system!) to move this object into. This method must fail if $obj is a container and $force isn't given or is false.

If you move a container using the $force option, and you have references to files held within that container, all of those references are probably now invalid.

$copy = $obj->copy($to, $force)

Copies the file to the given path. This object should refer to the original. The object representing the copy is returned. The c<$to> argument must refer to a reference to a file system container (from the same file system!). This method must fail if $obj is a container and $force isn't given or is false.

$obj->remove($force)

Deletes the object from the file system entirely. In general, this means that the object is now completely invalid.

The $force option, when set to a true value, will remove containers and all their children and children of children, etc.

$type = $obj->object_type

Synonym for:

$type = $obj->get_property("object_type");

The value returned is a string containing an arbitrary number of characters describing the type of the file system object. The following are defined:

d

This object may contain other files.

f

This object may have content.

$test = $obj->has_content

Returns a true value if the object contains file content. See "CONTENT METHODS" for additional methods.

This is equivalent to:

$obj->object_type =~ /f/;
$test = $obj->is_container

Returns a true value if the object may container other objects. See "CONTAINER METHODS" for additional methods.

This is equivalent to:

$obj->object_type =~ /d/;

CONTENT METHODS

These methods are provided if has_content returns a true value.

$test = $obj->is_readable

This returns a true value if the file data can be read from---this doesn't refer to file permissions, but to actual capabilities. Can someone read the file? This literally means, "Can the file be read as a stream?"

$test = $obj->is_seekable

This returns a true value if the file data is available for random-access. This literally means, "Are the individual bytes of the file addressable?"

$test = $obj->is_writable

This returns a true value if the file data can be written to---this doesn't refer to file permissions, but to actual capabilities. Can someone write to the file? This literally means, "Can the file be overwritten?"

TODO Can this be inferred from is_seekable and is_appendable?

$test = $obj->is_appendable

This returns a true value if the file data be appended to. This literally means, "Can the file be written to as a stream?"

$fh = $obj->open($access)

Using the same permissions, $access, as FileHandle, this method returns a file handle or a false value on failure.

$content = $obj->content
@lines = $obj->content

In scalar context, this method returns the whole file in a single scalar. In list context, this method returns the whole file as an array of lines (with the newline terminator defined for the current system left intact).

CONTAINER METHODS

These methods are provided if is_container returns a true value.

$test = $obj->has_children

Returns true if this container has any child objects (i.e., any child objects in addition to the mandatory '.' and '..').

@paths = $obj->children_paths

Returns the relative paths of all children of the given container. The first two paths should always be '.' and '..', respectively. These two paths should be present within anything that returns true for is_container.

@children = $obj->children

Returns the child File::System::Objects for all the actual children of this container. This is approxmiately the same as:

@children = map { $vfs->lookup($_) } grep !/^\.\.?$/, $obj->children_paths;

Notice that the objects for '.' and '..' are not returned.

$child = $obj->child($name)

Returns the child File::System::Object that matches the given $name or undef.

FILE SYSTEM PATHS

Paths are noted as follows:

"/"

The "/" alone represents the ultimate root of the file system.

"filename"

File names may contain any character except the forward slash.

The underlying file system may not be able to cope with all characters. As such, it is legal for a file system module to throw an exception if it is not able to cope with a given file name.

Files can never have the name "." or ".." because of their special usage (see below).

"filename1/filename2"

The slash is used to indicate that "filename2" is contained within "filename1". In general, the file system module doesn't really cope with "relative" file names, as might be indicated here. However, the File::System::Object does provide this functionality in a way.

"."

The single period indicates the current file. It is legal to embed multiples of these into a file path (e.g., "/./././././././" is still the root). Technically, the "." may only refer to files that may contain other files (otherwise the term makes no sense). In canonical form, all "." will be resolved by simply being removed from the path. (For example, "/./foo/./bar/./." is "/foo/bar" in canonical form.)

The single period has another significant "feature". If a single period is placed at the start of a file name it takes on the Unix semantic of a "hidden file". Basically, all that means is that a glob wishing to match such a file must explicit start with a '.'.

".."

The double period indicates the parent container. In the case of the root container, the root's parent is itself. In canonical form, all ".." will be resolved by replacing everything up to the ".." with the parent path. (For example, "/../foo/../bar/baz/.." is "/bar" in canonical form.)

"////"

All adjacent slashes are treated as a single slash. Thus, in canonical form, multiple adjacent slashes will be condenced into a single slash. (For example, "////foo//bar" is "/foo/bar" in canonical form.)

"?"

This character has special meaning in file globs. In a file glob it will match exactly one of any character. If you want to mean literally "?" instead, escape it with a backslash.

"*"

This character has special meaning in file globs. In a file glob it will match zero or more of any character non-greedily. If you want to mean literally "*" instead, escape it with a backslash.

"{a,b,c}"

The curly braces can be used to surround a comma separated list of alternatives in file globbing. If you mean a literal set of braces, then you need to escape them with a backslash.

"[abc0-9]"

The square brackets can be used to match any character within the given character class. If you mean a literal set of brackets, then you need to escape them with a backslash.

MODULE AUTHORS

If you wish to extend this interface to provide a new implementation, do so by creating a class that subclasses File::System::Object. That class must then define several methods. In the process you may override any method of this object, but make sure it adheres to the interface described in the documentation.

package My::File::Sytem::Implementation;

use strict;
use warnings;

use base qw( File::System::Object );

# define your implementation...

Below are lists of the methods you must or should define for your implementation. There is also a section below containing documentation for additional helper methods module authors should find useful, but general users probably won't.

MUST DEFINE

A subclass of File::System::Object must define the following methods:

root
is_creatable
create
is_valid
properties
settable_properties
get_property
set_property
rename
move
copy
remove

The following methods must be provided if your file system object implementation may return a true value for the has_content() method.

is_readable
is_seekable
is_writable
is_appendable
open
content

The following methods are container methods and must be defined if your file system object implementation may return true from the is_container() method.

has_children
children_paths
children
child

SHOULD DEFINE

A subclass of File::System::Object ought to consider defining better implementations of the following. Once all the methods above are defined correctly, these methods will work. However, they may not work efficiently.

Any methods not listed here or in "MUST DEFINE" have default implementations that are generally adequate. Also, the methods listed below in "HELPER METHODS" probably shouldn't be overriden.

exists
glob

HELPER METHODS

This class also provides a few helpers that may be useful to module uathors, but probably not of much use to typical users.

$clean_path = $obj->normalize_path($messy_path)

This method creates a canonical path out of the given path $messy_path. This is the single most important method offered to module authors. It provides several things:

  1. If the path being canonified is relative, this method checks to see if the current object is a container. Paths are relative to the current object if the current object is container. Otherwise, the paths are relative to this object's parent.

  2. Converts all relative paths to absolute paths.

  3. Removes all superfluous '.' and '..' names so that it gives the most concise and direct name for the named file.

  4. Enforces the principle that '..' applied to the root returns the root. This provides security by preventing users from getting to a file outside of the root (assuming that is possible for a given file system implementation).

Always, always, always use this method to clean up your paths.

@matched_paths = $obj->match_glob($glob, @all_paths)

This will match the given glob pattern $glob against the given paths @all_paths and will return only those paths that match. This provides a de facto implementation of globbing so that any module can provide this functionality without having to invent this functionality or rely upon a third party module.

$basename = $obj->basename_of_path($normalized_path)

Given a normalized path, this method will return the basename for that path according to the rules employed by File::System. (Essentially, they are the same as File::Basename, except that the basename of "/" is "/" rather than "".)

$dirname = $obj->dirname_of_path($normalized_path)

Given a normalized path, this method will return the dirname for that path according to the rules employed by File::System. (These should be identical to the rules used by File::Basename as far as I know.)

SEE ALSO

File::System

AUTHOR

Andrew Sterling Hanenkamp, <hanenkamp@users.sourceforge.net>

COPYRIGHT AND LICENSE

Copyright 2005 Andrew Sterling Hanenkamp. All Rights Reserved.

This software is distributed and licensed under the same terms as Perl itself.