File Coverage

blib/lib/Repository/Simple/Util.pm
Criterion Covered Total %
statement 12 45 26.6
branch 0 24 0.0
condition 0 3 0.0
subroutine 4 7 57.1
pod 3 3 100.0
total 19 82 23.1


line stmt bran cond sub pod time code
1             package Repository::Simple::Util;
2              
3 1     1   5 use strict;
  1         2  
  1         34  
4 1     1   4 use warnings;
  1         2  
  1         40  
5              
6             our $VERSION = '0.06';
7              
8 1     1   6 use Carp;
  1         2  
  1         80  
9              
10 1     1   5 use Exporter;
  1         3  
  1         572  
11              
12             our @ISA = qw( Exporter );
13             our @EXPORT_OK = qw(
14             normalize_path
15             basename
16             dirname
17             );
18              
19             our @CARP_NOT = qw(
20             Repository::Simple::Engine
21             Repository::Simple::Node
22             Repository::Simple::Permission
23             Repository::Simple::Property
24             Repository::Simple::Type::Node
25             Repository::Simple::Type::Property
26             Repository::Simple::Type::Value
27             Repository::Simple::Value
28             Repository::Simple
29             );
30              
31             =head1 NAME
32              
33             Repository::Simple::Util - Utility methods shared by repository components
34              
35             =head1 SYNOPSIS
36              
37             use Repository::Simple::Util qw( normalize_path dirname basename );
38              
39             my $clean_path = normalize_path("/usr", "../messy/../.././///messy/path");
40              
41             my $dirname = dirname("/foo/bar/baz"); # returns "/foo/bar"
42             my $basename = basename("/foo/bar/baz"); # returns "baz"
43              
44             =head1 DESCRIPTION
45              
46             The methods here are for use by the content repository and content repository engines internally. Unless you are extending the repository system, you will probably want to avoid the use of these methods.
47              
48             =head1 METHODS
49              
50             =over
51              
52             =item $clean_path = normalize_path($current_path, $messy_path)
53              
54             This method creates a "normal" path out of the given "messy" path, C<$messy_path>. In case the C<$messy_path> is relative, the C<$current_path> gives the absolute path we're working from.
55              
56             It provides the following:
57              
58             =over
59              
60             =item 1.
61              
62             If the messy path is relative, this method merges the messy path and the current path to create an absolute path.
63              
64             =item 2.
65              
66             All superfluous "." and ".." elements will be stripped from the path so that the resulting path will be the most concise and direct name for the named file.
67              
68             =item 3.
69              
70             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.
71              
72             =back
73              
74             =cut
75              
76             sub normalize_path {
77 0     0 1   my ($current_path, $messy_path) = @_;
78              
79 0 0         if (!defined $current_path) {
80 0           croak "normalize_path must be given a current path";
81             }
82              
83 0 0         if (!defined $messy_path) {
84 0           croak "normalize_path must be given a messy path";
85             }
86              
87             # Fix us up to an absolute path
88 0           my $abs_path;
89 0 0         if ($messy_path !~ m#^/#) {
90 0           $abs_path = "$current_path/$messy_path";
91             }
92             else {
93 0           $abs_path = $messy_path;
94             }
95              
96             # Break into components
97 0           my @components = split m#/+#, $abs_path;
98 0 0         @components = ('', '') unless @components; # account for root
99 0 0         unshift @components, '' unless @components > 1;
100              
101             # Manipulate the path components based upon each entry, work left-to-right
102             # to ensure proper handling of each component.
103 0           for (my $i = 1; $i < @components;) {
104             # Drop any "." components
105 0 0 0       if ($components[$i] eq '.') {
    0          
    0          
106 0           splice @components, $i, 1;
107             }
108              
109             # Drop any ".." that go above root
110             elsif ($components[$i] eq '..' && $i == 1) {
111 0           splice @components, $i, 1;
112             }
113              
114             # Drop any ".." and the component above
115             elsif ($components[$i] eq '..') {
116 0           splice @components, ($i - 1), 2;
117 0           $i--;
118             }
119              
120             # Otherwise, do nothing and move on to the next element
121             else {
122 0           $i++;
123             }
124             }
125              
126             # Make sure to tack on an empty "" in case we're back to root
127 0 0         unshift @components, '' unless @components > 1;
128              
129             # Reassemble the result
130 0           return join '/', @components;
131             }
132              
133             =item $dirname = dirname($path)
134              
135             Given a normalized path, this returns the path with the last element stripped. That is, it returns the parent of the given path. If the root path ("/") is given, then the same path is returned.
136              
137             =cut
138              
139             sub dirname {
140 0     0 1   my $path = shift;
141              
142 0 0         if ($path eq '/') {
143 0           return '/';
144             }
145              
146             else {
147 0           my @components = split m{/}, $path;
148 0           pop @components;
149 0 0         push @components, '' if @components == 1;
150 0           return join '/', @components;
151             }
152             }
153              
154             =item $basename = basename($path)
155              
156             Given a normalized path, this method returns the last path element of the path. That is, it returns the last name in the path. If the root path ("/") is given, then the same is returned.
157              
158             =cut
159              
160             sub basename {
161 0     0 1   my $path = shift;
162              
163 0 0         if ($path eq '/') {
164 0           return '/';
165             }
166              
167             else {
168 0           my @components = split m{/}, $path;
169 0           return pop @components;
170             }
171             }
172              
173             =back
174              
175             =head1 AUTHOR
176              
177             Andrew Sterling Hanenkamp, Ehanenkamp@cpan.orgE
178              
179             =head1 LICENSE AND COPYRIGHT
180              
181             Copyright 2005 Andrew Sterling Hanenkamp Ehanenkamp@cpan.orgE. All
182             Rights Reserved.
183              
184             This module is free software; you can redistribute it and/or modify it under
185             the same terms as Perl itself. See L.
186              
187             This program is distributed in the hope that it will be useful, but WITHOUT
188             ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
189             FOR A PARTICULAR PURPOSE.
190              
191             =cut
192              
193             1