1
<?php
2
/**
3
 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
4
 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
5
 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
6
 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
7
 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
8
 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
9
 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
10
 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
11
 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
12
 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
13
 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
14
 *
15
 * This software consists of voluntary contributions made by many individuals
16
 * and is licensed under the LGPL. For more information please see
17
 * <http://phing.info>.
18
 */
19

20
/**
21
 * UnixFileSystem class. This class encapsulates the basic file system functions
22
 * for platforms using the unix (posix)-stylish filesystem. It wraps php native
23
 * functions suppressing normal PHP error reporting and instead uses Exception
24
 * to report and error.
25
 *
26
 * This class is part of a oop based filesystem abstraction and targeted to run
27
 * on all supported php platforms.
28
 *
29
 * Note: For debugging turn track_errors on in the php.ini. The error messages
30
 * and log messages from this class will then be clearer because $php_errormsg
31
 * is passed as part of the message.
32
 *
33
 * FIXME:
34
 *  - Comments
35
 *  - Error handling reduced to min, error are handled by PhingFile mainly
36
 *
37
 * @author Andreas Aderhold, andi@binarycloud.com
38
 *
39
 * @package phing.system.io
40
 */
41
class UnixFileSystem extends FileSystem
42
{
43
    /**
44
     * returns OS dependent path separator char
45
     *
46
     * @return string
47
     */
48 1
    public function getSeparator()
49
    {
50 1
        return '/';
51
    }
52

53
    /**
54
     * returns OS dependent directory separator char
55
     *
56
     * @return string
57
     */
58 1
    public function getPathSeparator()
59
    {
60 1
        return ':';
61
    }
62

63
    /**
64
     * A normal Unix pathname contains no duplicate slashes and does not end
65
     * with a slash.  It may be the empty string.
66
     *
67
     * Check that the given pathname is normal.  If not, invoke the real
68
     * normalizer on the part of the pathname that requires normalization.
69
     * This way we iterate through the whole pathname string only once.
70
     *
71
     * NOTE: this method no longer expands the tilde (~) character!
72
     *
73
     * @param string $strPathname
74
     *
75
     * @return string
76
     */
77 1
    public function normalize($strPathname)
78
    {
79 1
        if (!strlen($strPathname)) {
80 1
            return '';
81
        }
82

83
        // Start normalising after any scheme that is present.
84
        // This prevents phar:///foo being normalised into phar:/foo
85
        // Use a regex as some paths may not by parsed by parse_url().
86 1
        if (preg_match('{^[a-z][a-z0-9+\-\.]+://}', $strPathname)) {
87 0
            $i = strpos($strPathname, '://') + 3;
88
        } else {
89 1
            $i = 0;
90
        }
91

92 1
        $n = strlen($strPathname);
93 1
        $prevChar = 0;
94 1
        for (; $i < $n; $i++) {
95 1
            $c = $strPathname[$i];
96 1
            if (($prevChar === '/') && ($c === '/')) {
97 1
                return self::normalizer($strPathname, $n, $i - 1);
98
            }
99 1
            $prevChar = $c;
100
        }
101 1
        if ($prevChar === '/') {
102 1
            return self::normalizer($strPathname, $n, $n - 1);
103
        }
104

105 1
        return $strPathname;
106
    }
107

108
    /**
109
     * Normalize the given pathname, whose length is $len, starting at the given
110
     * $offset; everything before this offset is already normal.
111
     *
112
     * @param string $pathname
113
     * @param int $len
114
     * @param int $offset
115
     *
116
     * @return string
117
     */
118 1
    protected function normalizer($pathname, $len, $offset)
119
    {
120 1
        if ($len === 0) {
121 0
            return $pathname;
122
        }
123 1
        $n = (int) $len;
124 1
        while (($n > 0) && ($pathname[$n - 1] === '/')) {
125 1
            $n--;
126
        }
127 1
        if ($n === 0) {
128 1
            return '/';
129
        }
130 1
        $sb = "";
131

132 1
        if ($offset > 0) {
133 1
            $sb .= substr($pathname, 0, $offset);
134
        }
135 1
        $prevChar = 0;
136 1
        for ($i = $offset; $i < $n; $i++) {
137 1
            $c = $pathname[$i];
138 1
            if (($prevChar === '/') && ($c === '/')) {
139 1
                continue;
140
            }
141 1
            $sb .= $c;
142 1
            $prevChar = $c;
143
        }
144

145 1
        return $sb;
146
    }
147

148
    /**
149
     * Compute the length of the pathname string's prefix.  The pathname
150
     * string must be in normal form.
151
     *
152
     * @param string $pathname
153
     *
154
     * @return int
155
     */
156 1
    public function prefixLength($pathname)
157
    {
158 1
        if (strlen($pathname) === 0) {
159 1
            return 0;
160
        }
161

162 1
        if (class_exists('Phar', false) && method_exists('Phar', 'running')) {
163 1
            $phar = Phar::running();
164 1
            $pharAlias = 'phar://' . Phing::PHAR_ALIAS;
165

166 1
            if ($phar && strpos($pathname, $phar) === 0) {
167 0
                return strlen($phar);
168
            }
169

170 1
            if ($phar && strpos($pathname, $pharAlias) === 0) {
171 0
                return strlen($pharAlias);
172
            }
173
        }
174

175 1
        return (($pathname[0] === '/') ? 1 : 0);
176
    }
177

178
    /**
179
     * Resolve the child pathname string against the parent.
180
     * Both strings must be in normal form, and the result
181
     * will be in normal form.
182
     *
183
     * @param string $parent
184
     * @param string $child
185
     *
186
     * @return string
187
     */
188 1
    public function resolve($parent, $child)
189
    {
190 1
        if ($child === "") {
191 1
            return $parent;
192
        }
193

194 1
        if ($child[0] === '/') {
195 0
            if ($parent === '/') {
196 0
                return $child;
197
            }
198

199 0
            return $parent . $child;
200
        }
201

202 1
        if ($parent === '/') {
203 0
            return $parent . $child;
204
        }
205

206 1
        return $parent . '/' . $child;
207
    }
208

209
    /**
210
     * @return string
211
     */
212 0
    public function getDefaultParent()
213
    {
214 0
        return '/';
215
    }
216

217
    /**
218
     * @param PhingFile $f
219
     *
220
     * @return bool
221
     */
222 1
    public function isAbsolute(PhingFile $f)
223
    {
224 1
        return ($f->getPrefixLength() !== 0);
225
    }
226

227
    /**
228
     * the file resolver
229
     *
230
     * @param PhingFile $f
231
     *
232
     * @return string
233
     */
234 1
    public function resolveFile(PhingFile $f)
235
    {
236
        // resolve if parent is a file oject only
237 1
        if ($this->isAbsolute($f)) {
238 1
            return $f->getPath();
239
        }
240

241 1
        return $this->resolve(Phing::getProperty("user.dir"), $f->getPath());
242
    }
243

244
    /* -- most of the following is mapped to the php natives wrapped by FileSystem */
245

246
    /* -- Attribute accessors -- */
247

248
    /**
249
     * compares file paths lexicographically
250
     *
251
     * @param  PhingFile $f1
252
     * @param  PhingFile $f2
253
     * @return int
254
     */
255 1
    public function compare(PhingFile $f1, PhingFile $f2)
256
    {
257 1
        $f1Path = $f1->getPath();
258 1
        $f2Path = $f2->getPath();
259

260 1
        return strcmp((string) $f1Path, (string) $f2Path);
261
    }
262

263
    /**
264
     * Copy a file, takes care of symbolic links
265
     *
266
     * @param PhingFile $src Source path and name file to copy.
267
     * @param PhingFile $dest Destination path and name of new file.
268
     *
269
     * @return void
270
     * @throws Exception if file cannot be copied.
271
     */
272 1
    public function copy(PhingFile $src, PhingFile $dest)
273
    {
274 1
        if (!$src->isLink()) {
275 1
            parent::copy($src, $dest);
276 1
            return;
277
        }
278

279 1
        $srcPath = $src->getAbsolutePath();
280 1
        $destPath = $dest->getAbsolutePath();
281

282 1
        $linkTarget = $src->getLinkTarget();
283 1
        if (false === @symlink($linkTarget, $destPath)) {
284 0
            $msg = "FileSystem::copy() FAILED. Cannot create symlink from $destPath to $linkTarget.";
285 0
            throw new Exception($msg);
286
        }
287
    }
288

289
    /**
290
     * @param string $p
291
     * @return string
292
     */
293 0
    public function fromURIPath($p)
294
    {
295 0
        if (StringHelper::endsWith("/", $p) && (strlen($p) > 1)) {
296
            // "/foo/" --> "/foo", but "/" --> "/"
297 0
            $p = substr($p, 0, strlen($p) - 1);
298
        }
299

300 0
        return $p;
301
    }
302

303
    /**
304
     * Whether file can be deleted.
305
     *
306
     * @param  PhingFile $f
307
     * @return boolean
308
     */
309 1
    public function canDelete(PhingFile $f)
310
    {
311 1
        @clearstatcache();
312 1
        $dir = dirname($f->getAbsolutePath());
313

314 1
        return @is_writable($dir);
315
    }
316
}

Read our documentation on viewing source code .

Loading