Commit 76e90b74 authored by Adrian Rossouw's avatar Adrian Rossouw Committed by adrian

Practically completely rewrote the provision_check_path function.

It is now called provision_path, and instead of the nasty switch statement it has a small set of pluggable  functions, which work similarly to theme() etc. For that reason I also ended up changing the order of the parameters to be provision_path('mkdir', 'somepath').

The functionality grew to over 200 lines of code (mostly comments), so i split it off into it's own file.

I also added checks that the user is in the correct group, and it will specify it to the user if it comes to it, but I should really hook it up into the user interface and write some better documentation about it before i can close #245664. Although it seems chgrp now fails silently for me, even from the command line. Please check it out.

I moved _provision_drupal_recursive_delete to provision.inc and removed the drupal from the module prefix. I also made it use the provision_path module for logging purposes, cleaning it up a bit.

#262008 is now completely fixed. I've re-added the permission checking in provision_drupal.module, since it now works. It was missing a clearstatcache(), so i added these pretty liberally.

Part of the fallout from this, is that each of the provision_path_ functions have an optional third parameter, which is a reference. This reference can be used to provide a reason for the operation failing. Also, mostly due to the chown function, i run the messages through t() before they get sent to logs. Meaning developers can just use @path and @confirm in their error messages, and they get the centrally prettied up variables. It's made the verify code a lot easier on the eyes. just check out provision_verify.

Added redirection to a new site maintenance page, for while the site is being restored.

Added a switch paths function, which flips around site directories. I'm building restore to be non-destructive, until after the site has been completely restored and verfied. #237555

I'm making a move to using more defines for various site infrastructure things. I just tackled the paths, will do the current user and current group stuff soon, bringing it back in line with hosting. It cleared up a fair amount of code just doing the paths.
parent 361580ae
......@@ -24,7 +24,6 @@ function provision_drupal_provision_service() {
* @TODO: PROPER profile support
function provision_drupal_provision_configure() {
$template = _provision_drupal_default_template();
$profiles = file_scan_directory('./profiles', '\.profile$', array('.', '..', 'CVS'), 0, TRUE, 'name', 0);
// Don't need to choose profile if only one available.
if (sizeof($profiles) == 1) {
......@@ -118,8 +117,8 @@ function _provision_drupal_default_template() {
* because the modules might provide additional information about the site.
*/
function _provision_drupal_create_settings_file($url, &$data) {
if (provision_check_path("sites/$url/settings.php", "exists")) {
provision_check_path("sites/$url/settings.php","chmod", 0750);
if (provision_path("exists", "sites/$url/settings.php")) {
provision_path("chmod", "sites/$url/settings.php", 0750);
}
$fp = fopen("sites/$url/settings.php", "w");
......@@ -128,8 +127,8 @@ function _provision_drupal_create_settings_file($url, &$data) {
fclose($fp);
# Change the permissions of the file
provision_check_path("sites/$url/settings.php", "chmod", 0550);
provision_check_path("sites/$url/settings.php", "chgrp", provision_get_group_name());
provision_path("chmod", "sites/$url/settings.php", 0550);
provision_path("chgrp", "sites/$url/settings.php", provision_get_group_name(), 'worky', 'no worky', PROVISION_PERM_ERROR);
}
/**
......@@ -150,20 +149,23 @@ function _provision_drupal_create_directories($url, $profile = null) {
foreach ($paths as $path => $perm) {
if (!is_dir($path)) {
provision_check_path($path, "mkdir", true,
t("Created <code>%path</code>", array("%path" => $path)),
t("Could not create <code>%path</code>", array("%path" => $path)),
provision_path("mkdir", $path, true,
t("Created <code>@path</code>"),
t("Could not create <code>@path</code>"),
PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
}
provision_check_path($path, "chown", provision_get_script_owner(),
t("Changed ownership of <code>%path</code>", array("%path" => $path)),
t("Could not change ownership <code>%path</code>", array("%path" => $path)));#, PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
provision_check_path($path, "chgrp", provision_get_group_name(),
t("Changed group ownership of <code>%path</code>", array("%path" => $path)),
t("Could not change group ownership <code>%path</code>", array("%path" => $path)));
provision_check_path($path, "chmod", $perm,
t("Changed permissions of <code>%path</code> to %perms", array("%path" => $path, '%perms' => $perm)),
t("Could not change permissions <code>%path</code> to %perms", array("%path" => $path, '%perms' => $perm)));#, PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
provision_path("chown", $path, provision_get_script_owner(),
t("Changed ownership of <code>@path</code>"),
t("Could not change ownership <code>@path</code>"),
PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
provision_path("chgrp", $path, provision_get_group_name(),
t("Changed group ownership of <code>@path</code>"),
t("Could not change group ownership <code>@path</code>"));
provision_path("chmod", $path, $perm,
t("Changed permissions of <code>@path</code> to @confirm"),
t("Could not change permissions <code>@path</code> to @confirm"),
PROVISION_PERM_ERROR | PROVISION_INSTALL_ERROR );
}
}
......@@ -187,7 +189,6 @@ function _provision_drupal_switch_active_site($url = null) {
$_SERVER['REMOTE_ADDR'] = NULL;
$_SERVER['REQUEST_METHOD'] = NULL;
/**
* This code is sourced from bootstrap.inc. I am trying to avoid patching core, but it might
* be smarter to make a small patch to allow core to re-initialize itself more easily
......@@ -306,20 +307,20 @@ function _provision_drupal_install_schema($profile) {
* implementation of provision_verify
*/
function provision_drupal_provision_verify($url, &$data) {
provision_check_path("sites", "writable", true, t("Drupal sites directory is writable by the provisioning script"),
provision_path("writable", "sites", true, t("Drupal sites directory is writable by the provisioning script"),
t("Drupal sites directory is not writable by the provisioning script"), PROVISION_PERM_ERROR);
$exists = provision_check_path(PROVISION_DRUSHRC_PATH, "exists", true ,
$exists = provision_path("exists", PROVISION_DRUSHRC_PATH, true ,
t("Virtual Host configuration path exists."),
t("Virtual Host configuration path does not exist."));
if (!$exists) {
$made = provision_check_path(PROVISION_DRUSHRC_PATH, "mkdir", true,
$made = provision_path("mkdir", PROVISION_DRUSHRC_PATH, true,
t("Virtual host configuration path has been created."),
t("Virtual host configuration path could not be created."),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR);
}
else {
$writable = provision_check_path(PROVISION_DRUSHRC_PATH, "writable", true ,
$writable = provision_path("writable", PROVISION_DRUSHRC_PATH, true ,
t("Virtual host configuration path is writable."),
t("Virtual host configuration path is not writable."),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR);
......@@ -334,7 +335,6 @@ function provision_drupal_provision_verify($url, &$data) {
// Find theme engines
$data['engines'] = drupal_system_listing('\.engine$', 'themes/engines');
$data['themes'] = system_theme_data();
$sites = provision_drupal_find_sites();
......@@ -342,45 +342,11 @@ function provision_drupal_provision_verify($url, &$data) {
$data['sites'] = array_keys($sites); // return list of hosted sites. used to determine whether or not to import.
}
/**
* Remove files or directories, recursively
*
* This was taken from imagecache.module, with slight modifications:
* - carry error codes along the way (returns true only if all operations return true)
* - remove any type of files encountered (not just links, files and dirs)
* - safety checking since we don't necessarly trust the removed files
*/
function _provision_drupal_recursive_delete($path) {
if (is_dir($path)) {
$d = dir($path);
while (($entry = $d->read()) !== false) {
if ($entry == '.' || $entry == '..') continue;
$entry_path = $path .'/'. $entry;
if (file_check_location($entry_path, $path)) {
$ret = _provision_drupal_recursive_delete($entry_path);
} else {
$ret = 0;
}
}
$rm = rmdir($path);
provision_log( ($rm) ? 'notice' : 'error', t("deleting @path directory @status", array('@path' => $path, '@status' => ($rm) ? 'successful' : 'failed')));
$ret = $ret && $rm;
}
else {
$rm = unlink($path);
if (!$rm) {
provision_log('error', "deleting $path file failed");
}
$ret = $ret && $rm;
}
return $ret;
}
/**
* Remove any directories for the site in sites/
*/
function provision_drupal_provision_delete($url, $data) {
return _provision_drupal_recursive_delete("sites/$url");
return _provision_recursive_delete("sites/$url");
}
function provision_drupal_find_sites() {
......@@ -389,15 +355,15 @@ function provision_drupal_find_sites() {
$path = explode("/", $file);
array_pop($path);
$sites[array_pop($path)] = $file;
}
return $sites;
}
function provision_drupal_restore($url, $backup_file, &$data) {
provision_shell_exec("tar -zxf %s -C sites/%s", $backup_file, $url); # checkout over old sites dir.
function provision_drupal_provision_pre_restore($url, $backup_file, &$data) {
}
function _provision_drupal_get_cvs_versions($files) {
foreach ($files as $modulename => $file) {
$project = array();
......@@ -434,7 +400,6 @@ function _provision_drupal_import_site($url) {
include_once("sites/$url/settings.php");
if ($parts = @parse_url($db_url)) {
$data['site_db_type'] = $parts['scheme'];
$data['site_db_user'] = $parts['user'];
......@@ -447,3 +412,4 @@ function _provision_drupal_import_site($url) {
}
return $data;
}
......@@ -258,8 +258,7 @@ function provision_get_site_data($url) {
}
$site_data['site_url'] = $url;
$site_data['site_action_type'] = $args['commands'][1];
$docroot = drush_get_option(array("r", "root"), $_SERVER['PWD']);
$site_data['publish_path'] = ($docroot) ? $docroot : $_SERVER['DOCUMENT_ROOT'];
$site_data['publish_path'] = PROVISION_DOCROOT_PATH;
$site_data['site_profile'] = ($site_data['site_profile']) ? $site_data['site_profile'] : variable_get('provision_default_profile', 'default');
$site_data['site_ip'] = variable_get('provision_apache_server_ip', '127.0.0.1');
$site_data['site_port'] = variable_get('provision_apache_server_ip', 80);
......@@ -374,22 +373,22 @@ function provision_render_config($template, $variables) {
* @} End of "defgroup provisionvalues".
*/
/**
* Confirm that provision is running through Drush.
*
* A safety mechanism to ensure that the drush commands are not run through the web front end.
*/
function provision_confirm_drush() {
return true;
}
/**
* Provide defines for all the major paths.
* Avoids duplication and possible errors in duplication
*/
function provision_init_paths() {
$path = ($_SERVER['PWD']) ? $_SERVER['PWD'] : $_SERVER['DOCUMENT_ROOT'];
if (function_exists('drush_get_option')) {
$docroot = drush_get_option(array("r", "root"), $_SERVER['PWD']);
}
else {
$docroot = $_SERVER['pwd'];
}
$path = ($docroot) ? $docroot : $_SERVER['DOCUMENT_ROOT'];
define('PROVISION_DOCROOT_PATH', rtrim($path, '/'));
define('PROVISION_SITES_PATH', rtrim($path, '/'));
$parts = explode("/", rtrim($path, '/'));
array_pop($parts);
......@@ -400,6 +399,41 @@ function provision_init_paths() {
}
/**
* Remove files or directories, recursively
*
* This was taken from imagecache.module, with slight modifications:
* - carry error codes along the way (returns true only if all operations return true)
* - remove any type of files encountered (not just links, files and dirs)
* - safety checking since we don't necessarly trust the removed files
*/
function _provision_recursive_delete($path) {
if (is_dir($path)) {
$d = dir($path);
while (($entry = $d->read()) !== false) {
if ($entry == '.' || $entry == '..') continue;
$entry_path = $path .'/'. $entry;
if (file_check_location($entry_path, $path)) {
$ret = _provision_recursive_delete($entry_path);
} else {
$ret = 0;
}
}
$rm = provision_path("rmdir", $path, true,
t("Deleting @path directory sucessful.", array('@path' => $path)),
t("Deleting @path directory failed.", array('@path' => $path)));
$ret = $ret && $rm;
}
else {
$rm = provision_path("unlink", $path, true, null,
t("Deleting @path file failed.", array('@path' => $path)));
$ret = $ret && $rm;
}
return $ret;
}
/**
* Wrapper around drush_shell_exec to provide sprintf functionality with some more safety.
*/
......@@ -462,65 +496,68 @@ function provision_get_group_name() {
}
/**
* Perform tests on directory.
* Check whether a user is a member of a group.
*
* Perform test on path, and log error messages / codes on failure.
* @param user
* username or user id of user.
* @param group
* groupname or group id of group.
*
* @return
* Boolean. True if user does belong to group,
* and false if the user does not belong to the group, or either the user or group do not exist.
*/
function provision_check_path($path, $type, $test = true, $succeed_message = '', $fail_message = '', $error_codes = null) {
# The code style is a bit weird here, but it's a bit easier to read this way.
switch ($type) {
case "writeable" :
case "writable" : $value = is_writable($path);
break;
case "exists" : $value = file_exists($path);
break;
case "readable" : $value = is_readable($path);
break;
case "is_dir" : $value = is_dir($path);
break;
case "owner" : $info = posix_getpwuid(fileowner($path));
$value = $info['name'];
break;
case "group" : $value = filegroup($path);
break;
case "mkdir" : $value = mkdir($path, 0770, true);
break;
case "chmod" : chmod($path, $test);
$test = (int) sprintf('%o', $test); # needs to be reset to oct
$value = (int) substr(sprintf('%o', fileperms($path)), -4);
break;
case "chown" : chown($path, $test);
if (!is_numeric($test)) {
$info = posix_getpwnam($test);
$test = $info['uid'];
}
$value = fileowner($path);
break;
case "chgrp" : chgrp($path, $test);
if (!is_numeric($test)) {
$info = posix_getgrnam($test);
$test = $info['gid'];
}
$value = filegroup($path);
break;
case "unlink" : $value = (file_exists($path)) ? unlink($path) : false;
break;
case "rmdir" : $value = (file_exists($path) && is_dir($path)) ? rmdir($path) : false;
break;
}
$status = ($value == $test);
if ($status) {
if ($succeed_message) {
provision_log("message", $succeed_message);
function provision_user_in_group($user, $group) {
// TODO: make these singletons with static variables for caching.
$user = provision_posix_username($user);
$group = provision_posix_groupname($group);
if ($user && $group) {
$info = posix_getgrnam($group);
if (in_array($user, $info['members'])) {
return TRUE;
}
}
return false;
}
/**
* Return the valid system username for $user.
*
* @return
* Returns the username if found, otherwise returns false
*/
function provision_posix_username($user) {
// TODO: make these singletons with static variables for caching.
// we do this both ways, so that the function returns null if no such user was found.
if (is_numeric($user)) {
$info = posix_getpwuid($user);
$user = $info['name'];
}
else {
if ($error_codes) {
provision_set_error($error_codes);
}
if ($fail_message) {
provision_log("error", $fail_message . " ($value != $test)");
}
$info = posix_getpwnam($user);
$user = $info['name'];
}
return $user;
}
/**
* Return the valid system groupname for $group.
*
* @return
* Returns the groupname if found, otherwise returns false
*/
function provision_posix_groupname($group) {
// TODO: make these singletons with static variables for caching.
// we do this both ways, so that the function returns null if no such user was found.
if (is_numeric($user)) {
$info = posix_getgrgid($group);
$group = $info['name'];
}
else {
$info = posix_getgrnam($group);
$group = $info['name'];
}
return $status;
return $group;
}
......@@ -33,14 +33,15 @@
* rename - Change the url of a site. This requires moving of files, and numerous other issues.
*/
// Include the provisioning API.
include_once('provision.inc');
include_once('provision.path.inc');
/**
* Implementation of hook_init
*/
function provision_init() {
// Include the provisioning API.
include_once('provision.inc');
// Set up defines for platform
provision_init_paths();
}
......@@ -94,6 +95,15 @@ function provision_menu($may_cache = true) {
'type' => MENU_CALLBACK,
'access' => user_access('access content'),
);
$items[] = array(
'path' => 'provision/maintenance',
'title' => t('Site is undergoing maintenance.'),
'description' => t('Page shown when a site is being restored or moved etc.'),
'callback' => 'provision_site_maintenance',
'type' => MENU_CALLBACK,
'access' => user_access('access content'),
);
}
return $items;
}
......@@ -203,6 +213,10 @@ function provision_disabled_site() {
return "<p>This site was disabled by the site administrators.</p>";
}
function provision_site_maintenance() {
return "<p>This site is being worked on presently. Check back later.</p>";
}
/**
* Menu callback.
*
......@@ -558,50 +572,56 @@ function _provision_import($url = null) {
* Will exit with a PROVISION_SITE_NOT_FOUND error if the site does not exist.
*/
function _provision_verify($url = '') {
$exists = provision_check_path(PROVISION_CONFIG_PATH, "exists", true ,
$exists = provision_path("exists",PROVISION_CONFIG_PATH, true ,
t("Provision configuration path exists."),
t("Provision configuration path does not exist."));
if (!$exists) {
$made = provision_check_path(PROVISION_CONFIG_PATH, "mkdir", true,
$made = provision_path("mkdir", PROVISION_CONFIG_PATH, true,
t("Provision configuration path has been created."),
t("Provision configuration could not be created."),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR);
}
provision_check_path(PROVISION_CONFIG_PATH, "writable", true ,
provision_path("writable", PROVISION_CONFIG_PATH, true ,
t("Provision configuration path is writable."),
t("Provision configuration path is not writable."),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR);
provision_check_path(PROVISION_CONFIG_PATH, "chown", provision_get_script_owner(),
t("Changed ownership of <code>%path</code>", array("%path" => $path)),
t("Could not change ownership <code>%path</code>", array("%path" => $path)),
provision_path("chown", PROVISION_CONFIG_PATH, provision_get_script_owner(),
t("Changed ownership of <code>@path</code>"),
t("Could not change ownership <code>@path</code>"),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR );
provision_check_path(PROVISION_CONFIG_PATH, "chmod", 0700,
t("Changed permissions of <code>%path</code> to %perms", array("%path" => $path, '%perms' => sprintf('%o', 0700))),
t("Could not change ownership <code>%path</code> to %perms", array("%path" => $path, '%perms' => sprintf('%o', 0700))),
provision_path("chmod", PROVISION_CONFIG_PATH, 0700,
t("Changed permissions of <code>@path</code> to @confirm"),
t("Could not change ownership <code>@path</code> to @confirm"),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR );
$exists = provision_check_path(PROVISION_BACKUP_PATH, "exists", true ,
$exists = provision_path("exists", PROVISION_BACKUP_PATH, true ,
t("Provision backup path exists."),
t("Provision backup path does not exist."));
if (!$exists) {
$made = provision_check_path(PROVISION_BACKUP_PATH, "mkdir", true,
$made = provision_path("mkdir", PROVISION_BACKUP_PATH, true,
t("Provision backup path has been created."),
t("Provision backup could not be created."),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR);
}
provision_check_path(PROVISION_BACKUP_PATH, "writable", true ,
provision_path("writable", PROVISION_BACKUP_PATH, true ,
t("Provision backup path is writable."),
t("Provision backup path is not writable."),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR);
provision_check_path(PROVISION_BACKUP_PATH, "chown", provision_get_script_owner(),
t("Changed ownership of <code>%path</code>", array("%path" => $path)),
t("Could not change ownership <code>%path</code>", array("%path" => $path)),
provision_path("chown", PROVISION_BACKUP_PATH, provision_get_script_owner(),
t("Changed ownership of <code>@path</code>"),
t("Could not change ownership <code>@path</code>"),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR );
provision_check_path(PROVISION_BACKUP_PATH, "chmod", 0700,
t("Changed permissions of <code>%path</code> to %perms", array("%path" => $path, '%perms' => sprintf('%o', 0700))),
t("Could not change ownership <code>%path</code> to %perms", array("%path" => $path, '%perms' => sprintf('%o', 0700))),
provision_path("chmod", PROVISION_BACKUP_PATH, 0700,
t("Changed permissions of <code>@path</code> to @confirm"),
t("Could not change ownership <code>@path</code> to @confirm"),
PROVISION_PERM_ERROR | PROVISION_FRAMEWORK_ERROR );
$data = array();
......@@ -612,6 +632,25 @@ function _provision_verify($url = '') {
provision_output($url, $data);
}
/**
* Restore command implementation
*
* This command when called will
* 1. Make a backup of the current site, before modifications are made.
* 2. Temporarily disable the site by causing apache to redirect to a help page. Restarting apache is required.
* 3. Extract the backup that is being restored to to a temporary folder in the sites directory.
* 4. Create a new database, belonging to the site's user, and switch it around with the current site's database.
* 5. Import the old database and site.php details.
* 6. Switch around the sites directory of the current site and the backup being restored.
* 7. Regenerate configuration files.
* 8. TODO: diagnostic to test that everything is ok?
* 9. Remove the temporary redirect and restart apache so the previous site is available again.
* 10. Remove the extranuous db and duplicate site directory.
*
* If at any time an error occurs, before step 9. It should reverse all the changes it has made,
* and leave the current site directory and database in the right place, and remove all cruft that
* was created by this process.
*/
function _provision_restore($site, $backup_file) {
if (!_provision_drupal_site_installed($url)) {
provision_log("Error", "Site has not been installed yet.");
......@@ -619,15 +658,23 @@ function _provision_restore($site, $backup_file) {
provision_output($url, $data);
}
if (!is_file($backup_file)) {
provision_log("File specified does not exist.");
provision_set_error(PROVISION_PERM_ERROR);
provision_path("exists", $backup_file, true,
t("Restoring site from @path"),
t("Could not find backup file @path"),
PROVISION_FRAMEWORK_ERROR);
provision_output($url, $data);
}
$data = provision_get_site_data($url);
_provision_backup_site($url, $data); # Backup site for posterity, before rolling back.
$rolled_back = provision_invoke("pre_restore", $url, $data); // if we need to make the site unavailable etc.
provision_shell_exec("tar -zxf %s -C %s/%s.tmp", $backup_file, PROVISION_BACKUP_PATH, $url); # check out old directory.
$rolled_back = provision_invoke("restore", $url, $data);
provision_shell_exec("tar -zxf %s -C %s/%s.restore", $backup_file, PROVISION_SITES_PATH, $url); # check out old directory.
$rolled_back = provision_invoke("restore", $url, $data); // do the actual database/file manipulation
_provision_recursive_delete(PROVISION_BACKUP_PATH . '/' . $url . '.tmp');
$rolled_back = provision_invoke("post_restore", $url, $data); // do the actual database/file manipulation
$data['site_installed'] = TRUE;
provision_save_site_data($url, $data);
......
<?php
/**
* @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 actions on a path.
*
* Perform actions 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.
* 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 actions 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 :
* 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 = '', $fail_message = '', $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 ($succeed_message) {
provision_log("message", t($succeed_message, $tokens));
}
}
else {
if ($error_codes) {
// Trigger a sysem halting error
provision_log("error", t($fail_message, $tokens));
provision_set_error($error_codes);
}
else {
// Trigger a warning
provision_log("warning", t($fail_message, $tokens));
}
}
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 (file_exists($path) && is_dir($path)) ? rmdir($path) : false;
}
function provision_path_unlink($path) {
return (file_exists($path)) ? unlink($path) : false;
}
/*
* This is where the more complex file operations start
*/
function provision_path_chmod($path, &$perms, &$reason) {
if (!chmod($path, $perms)) {
$reason = t('chmod failed');
return false;
}
clearstatcache(); // this needs to be called, otherwise we get the old info
$perms = sprintf('%o', $perms); # needs to be reset to oct
$value = substr(sprintf('%o', fileperms($path)), -4);
return $value;
}
function provision_path_chown($path, &$owner, &$reason) {
if ($owner = provision_posix_username($owner)) {
if (!chown($path, $owner)) {
$reason = t("chmod failed");
}
}
else {
$reason = t("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, &$group, &$reason) {