Skip to content

Commit 81e5107

Browse files
committed
Fix handling of files that are stored in a non executable folder.
1 parent b4c1923 commit 81e5107

File tree

1 file changed

+73
-3
lines changed

1 file changed

+73
-3
lines changed

src/PathPreserver.php

Lines changed: 73 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ public function preserve() {
8585
$relevant_paths = array();
8686
foreach ($this->preservePaths as $path) {
8787
$normalizedPath = $this->filesystem->normalizePath($path);
88-
if (file_exists($path) && strpos($normalizedPath, $installPathNormalized) === 0) {
88+
if (static::file_exists($path) && strpos($normalizedPath, $installPathNormalized) === 0) {
8989
$relevant_paths[] = $normalizedPath;
9090
}
9191
}
@@ -125,7 +125,7 @@ public function rollback() {
125125

126126
// Remove any code that was placed by the package at the place of
127127
// the original path.
128-
if (file_exists($original)) {
128+
if (static::file_exists($original)) {
129129
if (is_dir($original)) {
130130
$this->filesystem->emptyDirectory($original, false);
131131
$this->filesystem->removeDirectory($original);
@@ -137,14 +137,19 @@ public function rollback() {
137137
$this->io->write(sprintf('<comment>Files of installed package were overwritten with preserved path %s!</comment>', $original), true);
138138
}
139139

140-
$this->filesystem->ensureDirectoryExists(dirname($original));
140+
$folder = dirname($original);
141+
$this->filesystem->ensureDirectoryExists($folder);
142+
// Make sure we can write the file to the folder.
143+
$this->makePathWritable($folder);
141144
$this->filesystem->rename($backup_location, $original);
142145

143146
if ($this->filesystem->isDirEmpty(dirname($backup_location))) {
144147
$this->filesystem->removeDirectory(dirname($backup_location));
145148
}
146149
}
147150

151+
// Restore all path permissions, that where set for the sake of moving
152+
// things around.
148153
$this->restorePathPermissions();
149154

150155
// With a clean array, we can start over.
@@ -180,6 +185,12 @@ protected function preparePathPermissions($paths) {
180185
* @param string $path
181186
*/
182187
protected function makePathWritable($path) {
188+
// Make parent writable, before we can change the path itself.
189+
$parent = dirname($path);
190+
if ($parent != '.' && !is_writable($parent)) {
191+
$this->makePathWritable($parent);
192+
}
193+
183194
$this->filepermissions[$path] = fileperms($path);
184195
chmod($path, static::FILEPERM);
185196
}
@@ -198,4 +209,63 @@ protected function restorePathPermissions() {
198209
}
199210
}
200211

212+
/**
213+
* Check if file really exists.
214+
*
215+
* As php can only determine, whether a file or folder exists when the parent
216+
* directory is executable, we need to provide a workaround.
217+
*
218+
* @param $path
219+
* The path as in file_exists()
220+
*
221+
* @return bool
222+
* Returns TRUE if file exists, like in file_exists(),
223+
* but without restriction.
224+
*
225+
* @see file_exists()
226+
*/
227+
static public function file_exists($path) {
228+
229+
// Get all parent directories.
230+
$folders = array();
231+
$reset_perms = array();
232+
$folder = $path;
233+
while ($folder = dirname($folder)) {
234+
if ($folder === '.' || $folder === '/') {
235+
break;
236+
}
237+
elseif ($folder === '') {
238+
continue;
239+
}
240+
$folders[] = $folder;
241+
}
242+
243+
foreach (array_reverse($folders) as $current_folder) {
244+
// In the case a parent folder does not exist, the file cannot exist.
245+
if (!is_dir($current_folder)) {
246+
$return = FALSE;
247+
break;
248+
}
249+
// In the case the folder is really a folder, but not executable, we need
250+
// to change that, so we can check if the file really exists.
251+
elseif (!is_executable($current_folder)) {
252+
$reset_perms[$current_folder] = fileperms($current_folder);
253+
chmod($current_folder, 0755);
254+
}
255+
}
256+
257+
if (!isset($return)) {
258+
$return = file_exists($path);
259+
}
260+
261+
// Reset permissions in reverse order.
262+
foreach (array_reverse($reset_perms, TRUE) as $folder => $mode) {
263+
chmod($folder, $mode);
264+
}
265+
266+
return $return;
267+
}
268+
269+
270+
201271
}

0 commit comments

Comments
 (0)