Commit fe8994f1 authored by drumm's avatar drumm
Browse files

rebase

parent e567ae3a
<?php
// $Id$
/**
* @defgroup pathhandling Managing paths, permissions and file ownership
*
* This group provides an interface to common path handling operations, through
* the provision_path helper function, which will take care of verification and
* any error logging required.
*/
/**
* Perform tasks on a path.
*
* Perform tasks on a path, and logs error messages / codes on success or failure.
* This function will call another function which defines the functionality,
* and exists to provide a consistent interface for file operations with error logging
* integration.
*
* Many of the provision_path_$op functions are really simple, but are wrapped
* in functions to provide a consistent interface for provision_path to operate
* with.
*
* @param type
* The type of operation to perform. One of the following:
* writable - The $path can be written to.
* exists - The $path exists.
* is_dir - The $path is a directory.
* readable - The $path is readable.
* owner - The $path belongs to the user in $confirm.
* group - The $path belongs to the group in $confirm.
* mkdir - Create the $path directory.
* unlink - Delete the file $path.
* symlink - Create a symlink from $path to $confirm.
* rmdir - Delete the directory $path.
* chmod - Change the file permissions of $path to the octal value in $confirm.
* chown - Change the owner of $path to the user in $confirm.
* chgrp - Change the group of $path to the group in $confirm.
* switch_paths - Move $path to $confirm, and vice versa.
*
* @param path
* The path you want to perform the file operation on.
*
* @param confirm
* Confirm that the final value of the file operation matches this value.
* This value defaults to TRUE, which is sufficient for most file operations.
*
* Certain tasks such as chmod, chown and chgp will attempt to change the
* properties of $path to match the value in $confirm, and then test that
* the change was completed succesfully afterwards.
*
* These exceptions are :
* symlink - $confirm is the path to the symlink being created
* chmod - $confirm is an octal value denoting the desired file permissions.
* chown - $confirm is the name or user id you wish to change the file ownership to.
* chgrp - $confirm is the name of group id you wish to change the file group ownership to.
* switch_paths - $confirm is the path that you want to replace the $path with.
*
* @param succeed_message
* Log this as a notice into the logging system, if the operation completed succesfully.
*
* @param fail_message
* Log this as a error to the logging system, if the $error_codes parameter has been set,
* otherwise, log this as a warning. If the operation specifies an additional reason for
* the operation failing, it will be appended to this message.
*
* @param error_codes
* Generate these system level errors using the provision error bitmasks.
*
* @return
* Returns TRUE if the test against $confirm passed, otherwise returns FALSE.
*/
function provision_path($op, $path, $confirm = TRUE, $succeed_message = NULL, $fail_message = NULL, $error_codes = NULL) {
# The code style is a bit weird here, but it's a bit easier to read this way.
$func = "provision_path_" . $op;
if (function_exists($func)) {
// The reason variable is passed into the operation function, to allow the function
// to specify an additional reason as to why the operation failed.
$reason = '';
$value = $func($path, $confirm, $reason);
clearstatcache(); // this needs to be called, otherwise we get the old info
$tokens = array("@path" => $path, "@op" => $op, "@confirm" => $confirm);
if ($reason) {
$fail_message = $fail_message . " (" . $reason . ")";
}
$status = ($value == $confirm);
if ($status) {
if (!is_null($succeed_message)) {
drush_log(dt($succeed_message, $tokens), 'message');
}
}
else {
if ($error_codes) {
// Trigger a sysem halting error
if (!is_null($fail_message)) {
drush_set_error($error_codes, dt($fail_message, $tokens));
}
else {
drush_set_error($error_codes);
}
}
else {
// Trigger a warning
if (!is_null($fail_message)) {
drush_log(dt($fail_message, $tokens), 'warning');
}
}
}
return $status;
}
}
function provision_path_writable($path) {
return is_writable($path);
}
function provision_path_exists($path) {
return file_exists($path);
}
function provision_path_is_dir($path) {
return is_dir($path);
}
function provision_path_readable($path) {
return is_readable($path);
}
function provision_path_owner($path) {
$info = posix_getpwuid(fileowner($path));
return $info['name'];
}
function provision_path_group($path) {
return filegroup($path);
}
function provision_path_mkdir($path) {
return mkdir($path, 0770, TRUE);
}
function provision_path_rmdir($path) {
return rmdir($path);
}
function provision_path_unlink($path) {
return unlink($path);
}
/*
* This is where the more complex file operations start
*/
function provision_path_chmod($path, &$perms, &$reason, $recursive = FALSE) {
$func = ($recursive) ? '_provision_chmod_recursive' : 'chmod';
if (!@$func($path, $perms)) {
$reason = dt('chmod to @perm failed on @path', array('@perm' => sprintf('%o', $perms), '@path' => $path));
return false;
}
clearstatcache(); // this needs to be called, otherwise we get the old info
$value = substr(sprintf('%o', fileperms($path)), -4);
$perms = sprintf('%04o', $perms);
return $value;
}
function provision_path_chown($path, &$owner, &$reason, $recursive = FALSE) {
$func = ($recursive) ? '_provision_chown_recursive' : 'chown';
if ($owner = provision_posix_username($owner)) {
if (!$func($path, $owner)) {
$reason = dt("chown to @owner failed on @path", array('@owner' => $owner, '@path' => $path)) ;
}
}
else {
$reason = dt("the user does not exist");
}
clearstatcache(); // this needs to be called, otherwise we get the old info
return provision_posix_username(fileowner($path));
}
function provision_path_chgrp($path, &$gid, &$reason, $recursive = FALSE) {
$func = ($recursive) ? '_provision_chgrp_recursive' : 'chgrp';
if ($group = provision_posix_groupname($gid)) {
if (provision_user_in_group(drush_get_option('script_user'), $gid)) {
if ($func($path, $group)) {
return $group;
}
else {
$reason = dt("chgrp to @group failed on @path", array('@group' => $group, '@path' => $path));
}
}
else {
$reason = dt("@user is not in @group group", array("@user" => drush_get_option('script_user'), "@group" => $group));
}
}
elseif (!@$func($path, $gid)) { # try to change the group anyways
$reason = dt("the group does not exist");
}
clearstatcache(); // this needs to be called, otherwise we get the old info
return provision_posix_groupname(filegroup($path));
}
function provision_path_chmod_recursive($path, &$perms, &$reason) {
return provision_path_chmod($path, $perms, $reason, TRUE);
}
function provision_path_chown_recursive($path, &$owner, &$reason) {
return provision_path_chown($path, $owner, $reason, TRUE);
}
function provision_path_chgrp_recursive($path, &$gid, &$reason) {
return provision_path_chgrp($path, $gid, $reason, TRUE);
}
function provision_path_switch_paths($path1, &$path2, &$reason) {
//TODO : Add error reasons.
$temp = $path1 .'.tmp';
if (!file_exists($path1)) {
return rename($path2, $path1);
}
elseif (!file_exists($path2)) {
return rename($path1, $path2);
}
elseif (rename($path1, $temp)) {
if (rename($path2, $path1)) {
if (rename($temp, $path2)) {
return $path2; // path1 is now path2
}
else {
// same .. just in reverse
return rename($path1, $path2) && rename($temp, $path1);
}
}
else {
// same .. just in reverse
return rename($temp, $path1);
}
}
return FALSE;
}
function provision_path_extract($path, &$target, &$reason) {
if (file_exists($path) && is_readable($path)) {
if (is_writeable(dirname($target)) && !file_exists($target) && !is_dir($target)) {
mkdir($target);
$oldcwd = getcwd();
// we need to do this because some retarded implementations of tar (e.g. SunOS) don't support -C
chdir($target);
// same here: some do not support -z
$command = 'gunzip -c %s | tar pxf -';
drush_log(dt('Running: %command in %target', array('%command' => sprintf($command, $path), '%target' => $target)));
$result = provision_shell_exec($command, $path);
chdir($oldcwd);
if ($result && is_writeable(dirname($target)) && is_readable(dirname($target)) && is_dir($target)) {
$target = TRUE;
return TRUE;
}
else {
$reason = dt("The file could not be extracted");
}
}
else {
$reason = dt("The target directory could not be written to");
return false;
}
}
else {
$reason = dt("Backup file could not be opened");
return false;
}
}
function provision_path_symlink($path, &$target, &$reason) {
if (file_exists($target) && !is_link($target)) {
$reason = dt("A file already exists at @path");
return FALSE;
}
if (is_link($target) && (readlink($target) != $path)) {
$reason = dt("A symlink already exists at target, but it is pointing to @link", array("@link" => readlink($target)));
return FALSE;
}
if (is_link($target) && (readlink($target) == $path)) {
$target = TRUE;
return TRUE;
}
if (symlink($path, $target)) {
$target = TRUE;
return TRUE;
}
else {
$reason = dt('The symlink could not be created, an error has occured');
return FALSE;
}
}
/**
*@} end filegroup
*/
/**
* Small helper function for creation of configuration directories.
*/
function _provision_create_dir($path, $name, $perms) {
$exists = provision_path("exists",$path, TRUE ,
$name . ' ' . dt("path exists."),
$name . ' ' . dt("path does not exist.")
);
if (!$exists) {
$exists = provision_path("mkdir", $path, TRUE,
$name . ' ' . dt("path has been created."),
$name . ' ' . dt("path could not be created."),
'DRUSH_PERM_ERROR');
}
if ($exists) {
provision_path("chown", $path, drush_get_option('script_user'),
$name . ' ' . dt("ownership of path has been changed to @confirm."),
$name . ' ' . dt("ownership of path could not be changed to @confirm."),
'DRUSH_PERM_ERROR');
provision_path("chmod", $path, $perms,
$name . ' ' . dt("permissions of path have been changed to @confirm."),
$name . ' ' . dt("permissions of path could not be changed to @confirm."),
'DRUSH_PERM_ERROR' );
$writable = provision_path("writable", $path, TRUE,
$name . ' ' . dt("path is writable."),
$name . ' ' . dt("path is not writable."),
'DRUSH_PERM_ERROR');
}
return ($exists && $writable);
}
/**
* Walk the given tree recursively (depth first), calling a function on each file
*
* $func is not checked for existence and called directly with $path and $arg
* for every file encountered.
*
* @param string $func a valid callback, usually chmod, chown or chgrp
* @param string $path a path in the filesystem
* @param string $arg the second argument to $func
* @return boolean returns TRUE if every $func call returns true
*/
function _provision_call_recursive($func, $path, $arg) {
$status = 1;
// do not follow symlinks as it could lead to a DOS attack
// consider someone creating a symlink from files/foo to ..: it would create an infinite loop
if (!is_link($path) && ($dh = @opendir($path))) {
while (($file = readdir($dh)) !== false) {
if ($file != '.' && $file != '..') {
$status = _provision_call_recursive($func, $path . "/" . $file, $arg) && $status;
}
}
closedir($dh);
}
$status = $func($path, $arg) && $status;
return $status;
}
/**
* Chmod a directory recursively
*
*/
function _provision_chmod_recursive($path, $filemode) {
return _provision_call_recursive("chmod", $path, $filemode);
}
/**
* Chown a directory recursively
*/
function _provision_chown_recursive($path, $owner) {
return _provision_call_recursive("chown", $path, $owner);
}
/**
* Chgrp a directory recursively
*/
function _provision_chgrp_recursive($path, $owner) {
return _provision_call_recursive("chgrp", $path, $owner);
}
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment