forked from leftypol/leftypol
Compare commits
3 Commits
config
...
safer-thre
Author | SHA1 | Date | |
---|---|---|---|
1b74ab7d49 | |||
916b54a070 | |||
0325494cda |
|
@ -22,7 +22,8 @@
|
|||
"inc/queue.php",
|
||||
"inc/polyfill.php",
|
||||
"inc/error.php",
|
||||
"inc/functions.php"
|
||||
"inc/functions.php",
|
||||
"inc/functions/fs.php"
|
||||
]
|
||||
},
|
||||
"license": "Tinyboard + vichan",
|
||||
|
|
149
inc/functions/fs.php
Normal file
149
inc/functions/fs.php
Normal file
|
@ -0,0 +1,149 @@
|
|||
<?php
|
||||
|
||||
namespace Vichan\Functions;
|
||||
|
||||
|
||||
class FsUtils {
|
||||
public const MULTI_ERR_NONE = 0;
|
||||
public const MULTI_ERR_SRC_BAD = 1;
|
||||
public const MULTI_ERR_SRC_NO_PERM = 2;
|
||||
public const MULTI_ERR_TARGET_BAD = 3;
|
||||
public const MULTI_ERR_TARGET_NO_PERM = 4;
|
||||
public const MULTI_ERR_ACTION_FAILED = 5;
|
||||
|
||||
|
||||
private static function multiAction(array $config, string $src_dir, string $target_dir, iterable $src_file_names, callable $action, callable $action_rollback): int {
|
||||
if (!is_dir($src_dir)) {
|
||||
return self::MULTI_ERR_SRC_BAD;
|
||||
}
|
||||
if (!is_readable($src_dir)) {
|
||||
return self::MULTI_ERR_SRC_NO_PERM;
|
||||
}
|
||||
|
||||
if (!is_dir($target_dir)) {
|
||||
return self::MULTI_ERR_TARGET_BAD;
|
||||
}
|
||||
if (!is_writable($target_dir)) {
|
||||
return self::MULTI_ERR_TARGET_NO_PERM;
|
||||
}
|
||||
|
||||
$src_dir = self::ensureEndPathSeparator($src_dir);
|
||||
$target_dir = self::ensureEndPathSeparator($target_dir);
|
||||
|
||||
$linked = [];
|
||||
foreach ($src_file_names as $file_name) {
|
||||
$src_path = $src_dir . $file_name;
|
||||
$target_path = $target_dir . $file_name;
|
||||
|
||||
if (!file_exists($src_path)) {
|
||||
if ($config['syslog']) {
|
||||
_syslog(LOG_WARNING, "Attempting to operate on non-exiting file $src_path");
|
||||
}
|
||||
} else {
|
||||
$success = $action($src_path, $target_path);
|
||||
|
||||
if ($success) {
|
||||
$linked[] = $file_name;
|
||||
}
|
||||
// Rollback.
|
||||
else {
|
||||
if ($config['syslog']) {
|
||||
$l_count = count($linked);
|
||||
_syslog(LOG_ERR, "Failed to link $src_path in $target_dir, rolling back $l_count linked files.");
|
||||
}
|
||||
|
||||
foreach ($linked as $file_name) {
|
||||
$src_path = $src_dir . $file_name;
|
||||
$target_path = $target_dir . $file_name;
|
||||
|
||||
// Already falling back, ignore eventual errors and just log them.
|
||||
$success = $action_rollback($src_path, $target_path);
|
||||
if (!$success && $config['syslog']) {
|
||||
_syslog(LOG_ERR, "Failed to rollback $target_path in $src_dir.");
|
||||
}
|
||||
}
|
||||
|
||||
return self::MULTI_ERR_ACTION_FAILED;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return self::MULTI_ERR_NONE;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Appends a '/' to the given path if not already present.
|
||||
* @return string Returns the directory path terminating with a path separator.
|
||||
*/
|
||||
public static function ensureEndPathSeparator(string $dir): string {
|
||||
if ($dir[strlen($dir) - 1] !== '/') {
|
||||
return "$dir/";
|
||||
}
|
||||
return $dir;
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all the files or aborts and rolls back on error.
|
||||
* Implemented with file hardlinking.
|
||||
* @param array $config The configuration array.
|
||||
* @param string $src_dir The directory from which to fetch the files.
|
||||
* @param string $target_dir The directory to which the files should be copied to.
|
||||
* @param iterable $src_file_names The names of the files in $src_dir to be copied into $target_dir. The file names
|
||||
* may be path fragments, but must NOT begin with a path separator.
|
||||
* @return int Returns one of the class's MULTI_ERR_* constants.
|
||||
*/
|
||||
public static function multiCopy(array $config, string $src_dir, string $target_dir, iterable $src_file_names) {
|
||||
self::multiAction($config, $src_dir, $target_dir, $src_file_names, 'link', function($src_path, $target_path) {
|
||||
// Delete the hard links.
|
||||
\unlink($target_path);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Copies all the files or aborts and rolls back on error.
|
||||
* Implemented via file move.
|
||||
* @param array $config The configuration array.
|
||||
* @param string $src_dir The directory from which to fetch the files.
|
||||
* @param string $target_dir The directory to which the files should be copied to.
|
||||
* @param iterable $src_file_names The names of the files in $src_dir to be copied into $target_dir. The file names
|
||||
* may be path fragments, but must NOT begin with a path separator.
|
||||
* @return int Returns one of the class's MULTI_ERR_* constants.
|
||||
*/
|
||||
public static function multiMove(array $config, string $src_dir, string $target_dir, iterable $src_file_names) {
|
||||
self::multiAction($config, $src_dir, $target_dir, $src_file_names, 'rename', function ($src_path, $target_path) {
|
||||
// Move the files back into the source directory.
|
||||
\rename($target_path, $src_path);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes all the files in the given directory.
|
||||
*
|
||||
* @param string $src_dir The directory from which to delete the files.
|
||||
* @param iterable $src_file_names The names of the files in $src_dir to be deleted. The file names must NOT begin
|
||||
* with a path separator.
|
||||
* @return int Returns the number of deleted files.
|
||||
*/
|
||||
public function multiDelete(array $config, string $dir, iterable $file_names): int {
|
||||
$dir = self::ensureEndPathSeparator($dir);
|
||||
$deleted = 0;
|
||||
|
||||
foreach ($file_names as $file_name) {
|
||||
$target_path = $dir . $file_name;
|
||||
|
||||
$success = \unlink($target_path);
|
||||
|
||||
if ($success) {
|
||||
$deleted++;
|
||||
} elseif ($config['syslog']) {
|
||||
_syslog(LOG_ERR, "Failed to delete $target_path");
|
||||
}
|
||||
}
|
||||
|
||||
return $deleted;
|
||||
}
|
||||
|
||||
// Static class.
|
||||
private function __construct() {}
|
||||
}
|
Loading…
Reference in New Issue
Block a user