Completed
Push — master ( 89abc8...a320a7 )
by Siad
16:11
created

UnixFileSystem::setReadOnly()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 9
Code Lines 6

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 6

Importance

Changes 0
Metric Value
cc 2
eloc 6
nc 2
nop 1
dl 0
loc 9
ccs 0
cts 6
cp 0
crap 6
rs 10
c 0
b 0
f 0
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, [email protected]
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 395
    public function getSeparator()
49
    {
50 395
        return '/';
51
    }
52
53
    /**
54
     * returns OS dependent directory separator char
55
     *
56
     * @return string
57
     */
58 29
    public function getPathSeparator()
59
    {
60 29
        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 793
    public function normalize($strPathname)
78
    {
79 793
        if (!strlen($strPathname)) {
80 3
            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 793
        if (preg_match('{^[a-z][a-z0-9+\-\.]+://}', $strPathname)) {
87
            $i = strpos($strPathname, '://') + 3;
88
        } else {
89 793
            $i = 0;
90
        }
91
92 793
        $n = strlen($strPathname);
93 793
        $prevChar = 0;
94 793
        for (; $i < $n; $i++) {
95 793
            $c = $strPathname[$i];
96 793
            if (($prevChar === '/') && ($c === '/')) {
97 12
                return self::normalizer($strPathname, $n, $i - 1);
0 ignored issues
show
Bug Best Practice introduced by
The method UnixFileSystem::normalizer() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

97
                return self::/** @scrutinizer ignore-call */ normalizer($strPathname, $n, $i - 1);
Loading history...
98
            }
99 793
            $prevChar = $c;
100
        }
101 793
        if ($prevChar === '/') {
102 13
            return self::normalizer($strPathname, $n, $n - 1);
103
        }
104
105 790
        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 21
    protected function normalizer($pathname, $len, $offset)
119
    {
120 21
        if ($len === 0) {
121
            return $pathname;
122
        }
123 21
        $n = (int) $len;
124 21
        while (($n > 0) && ($pathname[$n - 1] === '/')) {
125 13
            $n--;
126
        }
127 21
        if ($n === 0) {
128 7
            return '/';
129
        }
130 17
        $sb = "";
131
132 17
        if ($offset > 0) {
133 14
            $sb .= substr($pathname, 0, $offset);
134
        }
135 17
        $prevChar = 0;
136 17
        for ($i = $offset; $i < $n; $i++) {
137 12
            $c = $pathname[$i];
138 12
            if (($prevChar === '/') && ($c === '/')) {
139 12
                continue;
140
            }
141 12
            $sb .= $c;
142 12
            $prevChar = $c;
143
        }
144
145 17
        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 790
    public function prefixLength($pathname)
157
    {
158 790
        if (strlen($pathname) === 0) {
159 1
            return 0;
160
        }
161
162 790
        if (class_exists('Phar', false) && method_exists('Phar', 'running')) {
163 790
            $phar = Phar::running();
164 790
            $pharAlias = 'phar://' . Phing::PHAR_ALIAS;
165
166 790
            if ($phar && strpos($pathname, $phar) === 0) {
167
                return strlen($phar);
168
            }
169
170 790
            if ($phar && strpos($pathname, $pharAlias) === 0) {
171
                return strlen($pharAlias);
172
            }
173
        }
174
175 790
        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 373
    public function resolve($parent, $child)
189
    {
190 373
        if ($child === "") {
191 2
            return $parent;
192
        }
193
194 373
        if ($child[0] === '/') {
195
            if ($parent === '/') {
196
                return $child;
197
            }
198
199
            return $parent . $child;
200
        }
201
202 373
        if ($parent === '/') {
203
            return $parent . $child;
204
        }
205
206 373
        return $parent . '/' . $child;
207
    }
208
209
    /**
210
     * @return string
211
     */
212
    public function getDefaultParent()
213
    {
214
        return '/';
215
    }
216
217
    /**
218
     * @param PhingFile $f
219
     *
220
     * @return bool
221
     */
222 784
    public function isAbsolute(PhingFile $f)
223
    {
224 784
        return ($f->getPrefixLength() !== 0);
225
    }
226
227
    /**
228
     * the file resolver
229
     *
230
     * @param PhingFile $f
231
     *
232
     * @return string
233
     */
234 784
    public function resolveFile(PhingFile $f)
235
    {
236
        // resolve if parent is a file oject only
237 784
        if ($this->isAbsolute($f)) {
238 784
            return $f->getPath();
239
        }
240
241 98
        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 6
    public function compare(PhingFile $f1, PhingFile $f2)
256
    {
257 6
        $f1Path = $f1->getPath();
258 6
        $f2Path = $f2->getPath();
259
260 6
        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 12
    public function copy(PhingFile $src, PhingFile $dest)
273
    {
274 12
        if (!$src->isLink()) {
275 10
            parent::copy($src, $dest);
276 10
            return;
277
        }
278
279 3
        $srcPath = $src->getAbsolutePath();
0 ignored issues
show
Unused Code introduced by
The assignment to $srcPath is dead and can be removed.
Loading history...
280 3
        $destPath = $dest->getAbsolutePath();
281
282 3
        $linkTarget = $src->getLinkTarget();
283 3
        if (false === @symlink($linkTarget, $destPath)) {
284
            $msg = "FileSystem::copy() FAILED. Cannot create symlink from $destPath to $linkTarget.";
285
            throw new Exception($msg);
286
        }
287 3
    }
288
289
    /**
290
     * @param string $p
291
     * @return string
292
     */
293
    public function fromURIPath($p)
294
    {
295
        if (StringHelper::endsWith("/", $p) && (strlen($p) > 1)) {
296
            // "/foo/" --> "/foo", but "/" --> "/"
297
            $p = substr($p, 0, strlen($p) - 1);
298
        }
299
300
        return $p;
301
    }
302
303
    /**
304
     * Whether file can be deleted.
305
     *
306
     * @param  PhingFile $f
307
     * @return boolean
308
     */
309 144
    public function canDelete(PhingFile $f)
310
    {
311 144
        @clearstatcache();
1 ignored issue
show
Security Best Practice introduced by
It seems like you do not handle an error condition for clearstatcache(). This can introduce security issues, and is generally not recommended. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-unhandled  annotation

311
        /** @scrutinizer ignore-unhandled */ @clearstatcache();

If you suppress an error, we recommend checking for the error condition explicitly:

// For example instead of
@mkdir($dir);

// Better use
if (@mkdir($dir) === false) {
    throw new \RuntimeException('The directory '.$dir.' could not be created.');
}
Loading history...
Bug introduced by
Are you sure the usage of clearstatcache() is correct as it seems to always return null.

This check looks for function or method calls that always return null and whose return value is used.

class A
{
    function getObject()
    {
        return null;
    }

}

$a = new A();
if ($a->getObject()) {

The method getObject() can return nothing but null, so it makes no sense to use the return value.

The reason is most likely that a function or method is imcomplete or has been reduced for debug purposes.

Loading history...
312 144
        $dir = dirname($f->getAbsolutePath());
313
314 144
        return @is_writable($dir);
315
    }
316
}
317