Updated to Drupal 8.5. Core Media not yet in use.
[yaffs-website] / vendor / drush / drush / includes / filesystem.inc
1 <?php
2
3 /**
4  * @file
5  * Filesystem utilities.
6  */
7 use Drush\Drush;
8 use Drush\Sql\SqlBase;
9 use Symfony\Component\Filesystem\Filesystem;
10 use Webmozart\PathUtil\Path;
11
12 /**
13  * @defgroup filesystemfunctions Filesystem convenience functions.
14  * @{
15  */
16
17 /**
18  * Behavior for drush_copy_dir() when destinations exist.
19  */
20 define('FILE_EXISTS_ABORT', 0);
21 define('FILE_EXISTS_OVERWRITE', 1);
22 define('FILE_EXISTS_MERGE', 2);
23
24 /**
25  * Deletes the specified file or directory and everything inside it.
26  *
27  * Usually respects read-only files and folders. To do a forced delete use
28  * drush_delete_tmp_dir() or set the parameter $forced.
29  *
30  * @param string $dir
31  *   The file or directory to delete.
32  * @param bool $force
33  *   Whether or not to try everything possible to delete the directory, even if
34  *   it's read-only. Defaults to FALSE.
35  * @param bool $follow_symlinks
36  *   Whether or not to delete symlinked files. Defaults to FALSE--simply
37  *   unlinking symbolic links.
38  *
39  * @return bool
40  *   FALSE on failure, TRUE if everything was deleted.
41  *
42  * @deprecated Use \Symfony\Component\Filesystem\Filesystem::remove.
43  */
44 function drush_delete_dir($dir, $force = FALSE, $follow_symlinks = FALSE) {
45   // Do not delete symlinked files, only unlink symbolic links
46   if (is_link($dir) && !$follow_symlinks) {
47     return unlink($dir);
48   }
49   // Allow to delete symlinks even if the target doesn't exist.
50   if (!is_link($dir) && !file_exists($dir)) {
51     return TRUE;
52   }
53   if (!is_dir($dir)) {
54     if ($force) {
55       // Force deletion of items with readonly flag.
56       @chmod($dir, 0777);
57     }
58     return unlink($dir);
59   }
60   if (drush_delete_dir_contents($dir, $force) === FALSE) {
61     return FALSE;
62   }
63   if ($force) {
64     // Force deletion of items with readonly flag.
65     @chmod($dir, 0777);
66   }
67   return rmdir($dir);
68 }
69
70 /**
71  * Deletes the contents of a directory.
72  *
73  * @param string $dir
74  *   The directory to delete.
75  * @param bool $force
76  *   Whether or not to try everything possible to delete the contents, even if
77  *   they're read-only. Defaults to FALSE.
78  *
79  * @return bool
80  *   FALSE on failure, TRUE if everything was deleted.
81  */
82 function drush_delete_dir_contents($dir, $force = FALSE) {
83   $scandir = @scandir($dir);
84   if (!is_array($scandir)) {
85     return FALSE;
86   }
87
88   foreach ($scandir as $item) {
89     if ($item == '.' || $item == '..') {
90       continue;
91     }
92     if ($force) {
93       @chmod($dir, 0777);
94     }
95     if (!drush_delete_dir($dir . '/' . $item, $force)) {
96       return FALSE;
97     }
98   }
99   return TRUE;
100 }
101
102 /**
103  * Copy $src to $dest.
104  *
105  * @param $src
106  *   The directory to copy.
107  * @param $dest
108  *   The destination to copy the source to, including the new name of
109  *   the directory.  To copy directory "a" from "/b" to "/c", then
110  *   $src = "/b/a" and $dest = "/c/a".  To copy "a" to "/c" and rename
111  *   it to "d", then $dest = "/c/d".
112  * @param $overwrite
113  *   Action to take if destination already exists.
114  *     - FILE_EXISTS_OVERWRITE - completely removes existing directory.
115  *     - FILE_EXISTS_ABORT - aborts the operation.
116  *     - FILE_EXISTS_MERGE - Leaves existing files and directories in place.
117  * @return
118  *   TRUE on success, FALSE on failure.
119  *
120  * @deprecated Use \Symfony\Component\Filesystem\Filesystem::copy.
121  */
122 function drush_copy_dir($src, $dest, $overwrite = FILE_EXISTS_ABORT) {
123   // Preflight based on $overwrite if $dest exists.
124   if (file_exists($dest)) {
125     if ($overwrite === FILE_EXISTS_OVERWRITE) {
126       drush_op('drush_delete_dir', $dest, TRUE);
127     }
128     elseif ($overwrite === FILE_EXISTS_ABORT) {
129       return drush_set_error('DRUSH_DESTINATION_EXISTS', dt('Destination directory !dest already exists.', array('!dest' => $dest)));
130     }
131     elseif ($overwrite === FILE_EXISTS_MERGE) {
132       // $overwrite flag may indicate we should merge instead.
133       drush_log(dt('Merging existing !dest directory', array('!dest' => $dest)));
134     }
135   }
136   // $src readable?
137   if (!is_readable($src)) {
138     return drush_set_error('DRUSH_SOURCE_NOT_EXISTS', dt('Source directory !src is not readable or does not exist.', array('!src' => $src)));
139   }
140   // $dest writable?
141   if (!is_writable(dirname($dest))) {
142     return drush_set_error('DRUSH_DESTINATION_NOT_WRITABLE', dt('Destination directory !dest is not writable.', array('!dest' => dirname($dest))));
143   }
144   // Try to do a recursive copy.
145   if (@_drush_recursive_copy($src, $dest)) {
146     return TRUE;
147   }
148
149   return drush_set_error('DRUSH_COPY_DIR_FAILURE', dt('Unable to copy !src to !dest.', array('!src' => $src, '!dest' => $dest)));
150 }
151
152 /**
153  * Internal function called by drush_copy_dir; do not use directly.
154  */
155 function _drush_recursive_copy($src, $dest) {
156   // all subdirectories and contents:
157   if(is_dir($src)) {
158     if (!mkdir($dest)) {
159       return FALSE;
160     }
161     $dir_handle = opendir($src);
162     while($file = readdir($dir_handle)) {
163       if ($file != "." && $file != "..") {
164         if (_drush_recursive_copy("$src/$file", "$dest/$file") !== TRUE) {
165           return FALSE;
166         }
167       }
168     }
169     closedir($dir_handle);
170   }
171   elseif (is_link($src)) {
172     symlink(readlink($src), $dest);
173   }
174   elseif (!copy($src, $dest)) {
175     return FALSE;
176   }
177
178   // Preserve file modification time.
179   // https://github.com/drush-ops/drush/pull/1146
180   touch($dest, filemtime($src));
181
182   // Preserve execute permission.
183   if (!is_link($src) && (!function_exists('drush_is_windows') || !drush_is_windows())) {
184     // Get execute bits of $src.
185     $execperms = fileperms($src) & 0111;
186     // Apply execute permissions if any.
187     if ($execperms > 0) {
188       $perms = fileperms($dest) | $execperms;
189       chmod($dest, $perms);
190     }
191   }
192
193   return TRUE;
194 }
195
196 /**
197  * Recursively create a directory tree.
198  *
199  * @param path
200  *   Path to directory to create.
201  *
202  * @throws IOException On any directory creation failure
203  * @deprecated See \Symfony\Component\Filesystem\Filesystem::mkdir.
204  */
205 function drush_mkdir($path) {
206   $fs = new Filesystem();
207   $fs->mkdir($path);
208   return true;
209 }
210
211 /*
212  * Determine if program exists on user's PATH.
213  *
214  * @return bool|null
215  */
216 function drush_program_exists($program) {
217   if (drush_has_bash()) {
218     $bucket = drush_bit_bucket();
219
220     // Remove environment variables (eg. PGPASSFILE=) before testing program.
221     $program = preg_replace('#^([A-Z0-9]+=.+? )+#', '', $program);
222
223     // Dont't use drush_op_system() since we don't want output during tests.
224     system("command -v $program > $bucket 2>&1", $result_code);
225     return $result_code === 0 ? TRUE : FALSE;
226   }
227 }
228
229 /**
230  * Save a string to a temporary file. Does not depend on Drupal's API.
231  * The temporary file will be automatically deleted when drush exits.
232  *
233  * @param string $data
234  * @param string $suffix
235  *   Append string to filename. use of this parameter if is discouraged. @see
236  *   drush_tempnam().
237  * @return string
238  *   A path to the file.
239  */
240 function drush_save_data_to_temp_file($data, $suffix = NULL) {
241   static $fp;
242
243   $file = drush_tempnam('drush_', NULL, $suffix);
244   $fp = fopen($file, "w");
245   fwrite($fp, $data);
246   $meta_data = stream_get_meta_data($fp);
247   $file = $meta_data['uri'];
248   fclose($fp);
249
250   return $file;
251 }
252
253 /**
254  * Returns the path to a temporary directory.
255  *
256  * @deprecated Use $this->getConfig()->tmp() in a ConfigAware command.
257  */
258 function drush_find_tmp() {
259   return Drush::config()->tmp();
260 }
261
262 /**
263  * Creates a temporary file, and registers it so that
264  * it will be deleted when drush exits.  Whenever possible,
265  * drush_save_data_to_temp_file() should be used instead
266  * of this function.
267  *
268  * @param string $suffix
269  *   Append this suffix to the filename. Use of this parameter is discouraged as
270  *   it can break the guarantee of tempname(). See http://www.php.net/manual/en/function.tempnam.php#42052.
271  *   Originally added to support Oracle driver.
272  */
273 function drush_tempnam($pattern, $tmp_dir = NULL, $suffix = '') {
274   if ($tmp_dir == NULL) {
275     $tmp_dir = Drush::config()->tmp();
276   }
277   $tmp_file = tempnam($tmp_dir, $pattern);
278   drush_register_file_for_deletion($tmp_file);
279   $tmp_file_with_suffix = $tmp_file . $suffix;
280   drush_register_file_for_deletion($tmp_file_with_suffix);
281   return $tmp_file_with_suffix;
282 }
283
284 /**
285  * Creates a temporary directory and return its path.
286  */
287 function drush_tempdir() {
288   $tmp_dir = Path::join(Drush::config()->tmp(), 'drush_tmp_' . uniqid(time() . '_'));
289
290   $fs = new Filesystem();
291   $fs->mkdir($tmp_dir);
292   drush_register_file_for_deletion($tmp_dir);
293
294   return $tmp_dir;
295 }
296
297 /**
298  * Any file passed in to this function will be deleted
299  * when drush exits.
300  */
301 function drush_register_file_for_deletion($file = NULL) {
302   static $registered_files = array();
303
304   if (isset($file)) {
305     if (empty($registered_files)) {
306       register_shutdown_function('_drush_delete_registered_files');
307     }
308     $registered_files[] = $file;
309   }
310
311   return $registered_files;
312 }
313
314 /**
315  * Delete all of the registered temporary files.
316  */
317 function _drush_delete_registered_files() {
318   $files_to_delete = drush_register_file_for_deletion();
319
320   foreach ($files_to_delete as $file) {
321     // We'll make sure that the file still exists, just
322     // in case someone came along and deleted it, even
323     // though they did not need to.
324     if (file_exists($file)) {
325       if (is_dir($file)) {
326         drush_delete_dir($file, TRUE);
327       }
328       else {
329         @chmod($file, 0777); // Make file writeable
330         unlink($file);
331       }
332     }
333   }
334 }
335
336 /**
337  * Test to see if a file exists and is not empty
338  */
339 function drush_file_not_empty($file_to_test) {
340   if (file_exists($file_to_test)) {
341     clearstatcache();
342     $stat = stat($file_to_test);
343     if ($stat['size'] > 0) {
344       return TRUE;
345     }
346   }
347   return FALSE;
348 }
349
350 /**
351  * Return 'TRUE' if one directory is located anywhere inside
352  * the other.
353  */
354 function drush_is_nested_directory($base_dir, $test_is_nested) {
355   $common = Path::getLongestCommonBasePath([$test_is_nested, $base_dir]);
356   return $common == Path::canonicalize($base_dir);
357 }
358
359 /**
360  * @} End of "defgroup filesystemfunctions".
361  */