$destination) { if (method_exists($destination, 'get_display_location')) { $dest_path = $destination->get_display_location(); if (!empty($dest_path) && file_valid_uri($dest_path)) { $scheme = file_uri_scheme($dest_path); // Support public and private storage and raw server paths. if ($scheme === 'private' || $scheme === 'public' || substr($dest_path, 0, 1) == '/') { // Check if the path exists. $path_exists = file_prepare_directory($dest_path, FILE_CREATE_DIRECTORY); if ($path_exists) { $real_path = drupal_realpath($dest_path); // See if the private path is somewhere inside the main Drupal // directory structure. if (strpos($real_path, DRUPAL_ROOT) === 0) { // Extract the relative path from the Drupal root path, and // then add the base URL, theoretically creating a fully // qualified URL to the storage directory. $url = substr($real_path, strlen(DRUPAL_ROOT) + 1); $url = url($url, array('absolute' => TRUE)); $result = drupal_http_request($url); // If the HTTP request comes back as a status 200 that means // there is a directory listing of some sort; directory paths // should return a 503 error. if (!empty($result->code) && $result->code == 200) { // Get the human readable information for this destination. $dest_spec = $destination->get_list_row(); // Display a warning message. $requirements['bmdest_' . $dest_name] = array( 'severity' => REQUIREMENT_ERROR, 'title' => 'Backup Migrate', 'value' => $t('Backup destination "%dest" is publicly accessible!', array('%dest' => $dest_spec['name'])), 'description' => $t('The backup destination, "%dest", stores its files in the "%path" directory. This directory is publicly available from the web server and urgently needs to be secured! Please see the Drupal manual on configuring the private directory path on how to fix this problem.', array( '%dest' => $dest_spec['name'], '%path' => $real_path, '@manual' => 'https://www.drupal.org/docs/7/core/modules/file/overview', )), ); } // Check an individual file. else { $files = scandir($real_path); if (!empty($files)) { foreach ($files as $file) { // Skip the base field pointers. if ($file == '.' || $file == '..') { continue; } $result = drupal_http_request($url . '/' . $file); // If the HTTP request comes back as a status 200 that // means the file is accessible. if (!empty($result->code) && $result->code == 200) { // Get the human readable information for this // destination. $dest_spec = $destination->get_list_row(); // Display a warning message. $requirements['bmdest_' . $dest_name] = array( 'severity' => REQUIREMENT_ERROR, 'title' => 'Backup Migrate', 'value' => $t('Files in "%dest" are publicly accessible!', array('%dest' => $dest_spec['name'])), 'description' => $t('The backup destination, "%dest", stores its files in the "%path" directory. These file(s) are publicly available from the web server and urgently need to be secured! Please see the Drupal manual on configuring the private directory path on how to fix this problem.', array( '%dest' => $dest_spec['name'], '%path' => $real_path, '@manual' => 'https://www.drupal.org/docs/7/core/modules/file/overview', )), ); } // Only need to check one file. break; } } } } } } } } } // Leave a note if there were no problems. // @todo No point in displaying this until the API has been expanded. // @code // if (empty($requirements)) { // $requirements['bmdest_' . $dest_name] = array( // 'severity' => REQUIREMENT_INFO, // 'title' => 'Backup Migrate', // 'value' => $t('Backup destinations are safe'), // 'description' => $t('The backup destinations were all checked and none of them were exposing files to the public. This is a good thing.'), // ); // } // @endcode if (variable_get('backup_migrate_disable_cron', FALSE)) { $requirements['bm_disable_cron'] = array( 'severity' => REQUIREMENT_INFO, 'title' => 'Backup Migrate', 'value' => $t('Cron tasks are disabled'), 'description' => $t('The cron tasks have been disabled, so scheduled backups will not run. See the Backup & Migrate module\'s README.txt file for further details.'), ); } } return $requirements; } /** * Implements hook_schema(). */ function backup_migrate_schema() { $schema['backup_migrate_profiles'] = array( 'export' => array( 'key' => 'machine_name', 'key name' => 'Profile ID', 'admin_title' => 'name', 'primary key' => 'profile_id', // Exports will be defined as $preset. 'identifier' => 'item', // Function hook name. 'default hook' => 'exportables_backup_migrate_profiles', 'api' => array( 'owner' => 'backup_migrate', // Base name for api include files. 'api' => 'backup_migrate_exportables', 'minimum_version' => 1, 'current_version' => 1, ), ), 'fields' => array( 'profile_id' => array( 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.', // Do not export database-only keys. 'no export' => TRUE, ), 'machine_name' => array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0', 'description' => 'The primary identifier for a profile.', ), 'name' => array( 'description' => 'The name of the profile.', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, ), 'filename' => array( 'description' => 'The name of the profile.', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, ), 'append_timestamp' => array( 'description' => 'Append a timestamp to the filename.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'timestamp_format' => array( 'description' => 'The format of the timestamp.', 'type' => 'varchar', 'length' => 14, 'not null' => TRUE, ), 'filters' => array( 'description' => 'The filter settings for the profile.', 'type' => 'text', 'not null' => TRUE, 'serialize' => TRUE, 'serialized default' => 'a:0:{}', ), ), 'primary key' => array('profile_id'), ); $schema['backup_migrate_destinations'] = array( 'export' => array( 'key' => 'machine_name', 'key name' => 'Destination ID', 'admin_title' => 'name', 'primary key' => 'destination_id', // Exports will be defined as $preset. 'identifier' => 'item', // Function hook name. 'default hook' => 'exportables_backup_migrate_destinations', 'api' => array( 'owner' => 'backup_migrate', // Base name for api include files. 'api' => 'backup_migrate_exportables', 'minimum_version' => 1, 'current_version' => 1, ), ), 'fields' => array( 'destination_id' => array( 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.', // Do not export database-only keys. 'no export' => TRUE, ), 'machine_name' => array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0', 'description' => 'The primary identifier for a destination.', ), 'name' => array( 'description' => 'The name of the destination.', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, ), 'subtype' => array( 'description' => 'The type of the destination.', 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, ), 'location' => array( 'description' => 'The the location string of the destination.', 'type' => 'text', 'not null' => TRUE, ), 'settings' => array( 'description' => 'Other settings for the destination.', 'type' => 'text', 'not null' => TRUE, 'serialize' => TRUE, 'serialized default' => 'a:0:{}', ), ), 'primary key' => array('destination_id'), ); $schema['backup_migrate_sources'] = array( 'export' => array( 'key' => 'machine_name', 'key name' => 'Source ID', 'admin_title' => 'name', 'primary key' => 'source_id', // Exports will be defined as $preset. 'identifier' => 'item', // Function hook name. 'default hook' => 'exportables_backup_migrate_sources', 'api' => array( 'owner' => 'backup_migrate', // Base name for api include files. 'api' => 'backup_migrate_exportables', 'minimum_version' => 1, 'current_version' => 1, ), ), 'fields' => array( 'source_id' => array( 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.', // Do not export database-only keys. 'no export' => TRUE, ), 'machine_name' => array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0', 'description' => 'The primary identifier for a source.', ), 'name' => array( 'description' => 'The name of the source.', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, ), 'subtype' => array( 'description' => 'The type of the source.', 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, ), 'location' => array( 'description' => 'The the location string of the source.', 'type' => 'text', 'not null' => TRUE, ), 'settings' => array( 'description' => 'Other settings for the source.', 'type' => 'text', 'not null' => TRUE, 'serialize' => TRUE, 'serialized default' => 'a:0:{}', ), ), 'primary key' => array('source_id'), ); $schema['backup_migrate_schedules'] = array( 'export' => array( 'key' => 'machine_name', 'key name' => 'Source ID', 'admin_title' => 'name', 'primary key' => 'schedule_id', // Exports will be defined as $preset. 'identifier' => 'item', // Function hook name. 'default hook' => 'exportables_backup_migrate_schedules', 'api' => array( 'owner' => 'backup_migrate', // Base name for api include files. 'api' => 'backup_migrate_exportables', 'minimum_version' => 1, 'current_version' => 1, ), ), 'fields' => array( 'schedule_id' => array( 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.', // Do not export database-only keys. 'no export' => TRUE, ), 'machine_name' => array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0', 'description' => 'The primary identifier for a profile.', ), 'name' => array( 'description' => 'The name of the profile.', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, ), 'source_id' => array( 'description' => 'The {backup_migrate_destination}.destination_id of the source to backup from.', 'type' => 'varchar', 'length' => 255, 'default' => 'db', 'not null' => TRUE, ), 'destination_id' => array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0', 'description' => 'The {backup_migrate_destination}.destination_id of the destination to back up to.', ), 'copy_destination_id' => array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => '0', 'description' => 'A second {backup_migrate_destination}.destination_id of the destination to copy the backup to.', ), 'profile_id' => array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0', 'description' => 'The primary identifier for a profile.', ), 'keep' => array( 'type' => 'int', 'not null' => TRUE, 'default' => 0, 'description' => 'The number of backups to keep.', ), 'period' => array( 'type' => 'int', 'not null' => TRUE, 'default' => 0, 'description' => 'The number of seconds between backups.', ), 'enabled' => array( 'description' => 'Whether the schedule is enabled.', 'type' => 'int', 'size' => 'tiny', 'unsigned' => TRUE, 'not null' => TRUE, 'default' => 0, ), 'cron' => array( 'description' => 'Whether the schedule should be run during cron.', 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => 'builtin', ), 'cron_schedule' => array( 'description' => 'The cron schedule to run on.', 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0 4 * * *', ), ), 'primary key' => array('schedule_id'), ); return $schema; } /** * Implements hook_uninstall(). */ function backup_migrate_uninstall() { variable_del('backup_migrate_backup_max_time'); variable_del('backup_migrate_copy_destination_id'); variable_del('backup_migrate_data_bytes_per_line'); variable_del('backup_migrate_data_rows_per_line'); variable_del('backup_migrate_data_rows_per_query'); variable_del('backup_migrate_destination_id'); variable_del('backup_migrate_disable_cron'); variable_del('backup_migrate_memory_limit'); variable_del('backup_migrate_profile_id'); variable_del('backup_migrate_schedule_last_run_'); variable_del('backup_migrate_source_id'); variable_del('backup_migrate_timeout_buffer'); variable_del('backup_migrate_verbose'); variable_del('nodesquirrel_endpoint_urls'); variable_del('nodesquirrel_schedule'); variable_del('nodesquirrel_schedule_enabled'); variable_del('nodesquirrel_schedule_source_id'); variable_del('nodesquirrel_secret_key'); } /** * Update from 1.x to 2.x. */ function backup_migrate_update_2000() { _backup_migrate_setup_database_defaults(); return array(); } /** * Adding filter field for dev release of 2009-01-28. */ function backup_migrate_update_2001() { $ret = array(); $schema = drupal_get_schema_unprocessed('backup_migrate', 'backup_migrate_profiles'); // Add the filters field to the db. if (!db_field_exists('backup_migrate_profiles', 'filters')) { db_add_field('backup_migrate_profiles', 'filters', array( 'description' => t('The filter settings for the profile.'), 'type' => 'text', 'not null' => TRUE, )); } // Add the source field. if (!db_field_exists('backup_migrate_profiles', 'source_id')) { db_add_field('backup_migrate_profiles', 'source_id', array( 'description' => t('The {backup_migrate_destination}.destination_id of the source to backup from.'), 'type' => 'varchar', 'length' => 255, 'default' => 'db', 'not null' => TRUE, )); } // Remove the compression field. if (db_field_exists('backup_migrate_profiles', 'compression')) { db_drop_field('backup_migrate_profiles', 'compression'); } return $ret; } /** * Clear the cache because there was a menu structure change. */ function backup_migrate_update_2002() { // Cache should clear automatically. Nothing to do here. return array(); } /** * Allowing non-int profile ids in schedules 2009-05-31. */ function backup_migrate_update_2003() { $ret = array(); $spec = array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0', 'description' => 'The primary identifier for a profile.', ); db_change_field('backup_migrate_schedules', 'profile_id', 'profile_id', $spec); return $ret; } /** * Allowing non-int profile ids 2009-07-01. */ function backup_migrate_update_2004() { $ret = array(); $spec = array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0', ); $spec['description'] = 'The primary identifier for a destination.'; db_change_field('backup_migrate_destinations', 'destination_id', 'destination_id', $spec); $spec['description'] = 'The primary identifier for a profile.'; db_change_field('backup_migrate_profiles', 'profile_id', 'profile_id', $spec); $spec['description'] = 'The primary identifier for a schedule.'; db_change_field('backup_migrate_schedules', 'schedule_id', 'schedule_id', $spec); // Drop the user/pass fields as they weren't being used. if (db_field_exists('backup_migrate_destinations', 'username')) { db_drop_field('backup_migrate_destinations', 'username'); } if (db_field_exists('backup_migrate_destinations', 'password')) { db_drop_field('backup_migrate_destinations', 'password'); } return $ret; } /** * Change the default database id to something friendlier 2009-08-08. */ function backup_migrate_update_2005() { require_once './' . drupal_get_path('module', 'backup_migrate') . '/includes/crud.inc'; require_once './' . drupal_get_path('module', 'backup_migrate') . '/includes/profiles.inc'; $ret = array(); // Change the destination ids of the defined database sources mostly to make // using them with drush friendlier. // Change the db_url:default id to simply 'db'. $ret[] = db_query("UPDATE {backup_migrate_profiles} SET source_id = 'db' WHERE source_id = 'db_url:default'"); $ret[] = db_query("UPDATE {backup_migrate_schedules} SET destination_id = 'db' WHERE destination_id = 'db_url:default'"); // Change the defined db keys from db_url:key to db:key. $ret[] = db_query("UPDATE {backup_migrate_profiles} SET source_id = REPLACE(source_id, 'db_url:', 'db:')"); $ret[] = db_query("UPDATE {backup_migrate_schedules} SET destination_id = REPLACE(destination_id, 'db_url:', 'db:')"); // Add the source field to the schedule. if (!db_field_exists('backup_migrate_schedules', 'source_id')) { db_add_field('backup_migrate_schedules', 'source_id', array( 'description' => t('The db source to backup from.'), 'type' => 'varchar', 'length' => 255, 'default' => 'db', 'not null' => TRUE, )); } // Copy source data from profiles to schedules. $result = db_query('SELECT p.source_id, s.schedule_id FROM {backup_migrate_schedules} s LEFT JOIN {backup_migrate_profiles} p ON s.profile_id = p.profile_id', array(), array('fetch' => PDO::FETCH_ASSOC)); foreach ($result as $schedule) { if (!$schedule['source_id']) { $schedule['source_id'] = 'db'; } $ret[] = db_query("UPDATE {backup_migrate_schedules} SET source_id = '" . $schedule['source_id'] . "' WHERE schedule_id = '" . $schedule['profile_id'] . "'"); } if (db_field_exists('backup_migrate_profiles', 'source_id')) { db_drop_field('backup_migrate_profiles', 'source_id'); } // Copy the no-data and exclude tables settings into the 'filter' field. $result = db_query('SELECT * FROM {backup_migrate_profiles}', array(), array('fetch' => PDO::FETCH_ASSOC)); foreach ($result as $item) { if (isset($item['nodata_tables']) && isset($item['exclude_tables'])) { $profile = backup_migrate_get_profile($item['profile_id']); $profile->filters['nodata_tables'] = unserialize($item['nodata_tables']); $profile->filters['exclude_tables'] = unserialize($item['exclude_tables']); $profile->save(); } } if (db_field_exists('backup_migrate_profiles', 'nodata_tables')) { db_drop_field('backup_migrate_profiles', 'nodata_tables'); } if (db_field_exists('backup_migrate_profiles', 'exclude_tables')) { db_drop_field('backup_migrate_profiles', 'exclude_tables'); } return $ret; } /** * Move the backup and migrate directory to the private directory. */ function backup_migrate_update_7200() { $from = 'public://backup_migrate'; $to = 'private://backup_migrate'; if (drupal_realpath($from) && !drupal_realpath($to)) { if (!rename($from, $to)) { drupal_set_message(t('Unable to move the backups directory to your private folder, please check file permissions and move the directory %from to %to', array('%from' => drupal_realpath($from), '%to' => drupal_realpath($to))), 'warning'); } } } /** * Change the filename field to support 255 characters. */ function backup_migrate_update_7202() { $ret = array(); db_change_field('backup_migrate_profiles', 'filename', 'filename', array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, )); return $ret; } /** * Schedule last run times to use variables instead of saving with the schedule. */ function backup_migrate_update_7203() { $result = db_query('SELECT * FROM {backup_migrate_schedules}', array(), array('fetch' => PDO::FETCH_ASSOC)); foreach ($result as $item) { if (isset($item['last_run'])) { variable_set('backup_migrate_schedule_last_run_' . $item['schedule_id'], $item['last_run']); } } if (db_field_exists('backup_migrate_schedules', 'last_run')) { db_drop_field('backup_migrate_schedules', 'last_run'); } } /** * Uninstall backup migrate files if it's installed. */ function backup_migrate_update_7300() { if (module_exists('backup_migrate_files')) { module_disable(array('backup_migrate_files')); $ret[] = array( 'success' => TRUE, 'query' => 'Disabled the Backup and Migrate Files module', ); } if (module_exists('nodesquirrel')) { module_disable(array('nodesquirrel')); $ret[] = array( 'success' => TRUE, 'query' => 'Disabled the NodeSquirrel module', ); } // Add sources to the schema. $schema['backup_migrate_sources'] = array( 'fields' => array( 'source_id' => array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => '0', 'description' => t('The primary identifier for a source.'), ), 'name' => array( 'description' => t('The name of the source.'), 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, ), 'type' => array( 'description' => t('The type of the source.'), 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, ), 'location' => array( 'description' => t('The the location string of the source.'), 'type' => 'text', 'not null' => TRUE, ), 'settings' => array( 'description' => t('Other settings for the source.'), 'type' => 'text', 'not null' => TRUE, 'serialize' => TRUE, 'serialized default' => 'a:0:{}', ), ), 'primary key' => array('source_id'), ); if (!db_table_exists('backup_migrate_sources')) { db_create_table('backup_migrate_sources', $schema['backup_migrate_sources']); } // Move custom destinations to sources. $result = db_query("SELECT * FROM {backup_migrate_destinations} WHERE type in ('filesource', 'db')", array(), array('fetch' => PDO::FETCH_ASSOC)); foreach ($result as $item) { $item['source_id'] = $item['destination_id']; drupal_write_record('backup_migrate_source', $item); } // Change 'destination' settings to 'source' settings. $result = db_query('SELECT * FROM {backup_migrate_profiles}', array(), array('fetch' => PDO::FETCH_ASSOC)); foreach ($result as $item) { $item['filters'] = unserialize($item['filters']); $item['filters']['sources'] = $item['filters']['destinations']; unset($item['filters']['destinations']); drupal_write_record('backup_migrate_profiles', $item, array('profile_id')); } } /** * Switch the cron switch to text. */ function backup_migrate_update_7301() { db_change_field('backup_migrate_schedules', 'cron', 'cron', array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => 'builtin', )); db_add_field('backup_migrate_schedules', 'cron_schedule', array( 'description' => 'The cron schedule to run on.', 'type' => 'varchar', 'length' => 255, 'default' => '0 4 * * *', 'not null' => TRUE, )); } /** * Add a second destination to schedules. */ function backup_migrate_update_7302() { db_add_field('backup_migrate_schedules', 'copy_destination_id', array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => '0', 'description' => 'A second {backup_migrate_destination}.destination_id of the destination to copy the backup to.', ) ); } /** * Add a serial id field to all tables to allow them to be ctools exportable. */ function backup_migrate_update_7303() { foreach (array( 'backup_migrate_sources' => 'source_id', 'backup_migrate_destinations' => 'destination_id', 'backup_migrate_schedules' => 'schedule_id', 'backup_migrate_profiles' => 'profile_id', ) as $table => $id) { // Take the primary key status from the machine name so it can be renamed // A serial field must be defined as a key, so make a temporary index. // See: https://www.drupal.org/node/190027 db_add_index($table, 'temp', array($id)); db_drop_primary_key($table); // Drop our temporary index. db_drop_index($table, 'temp'); // Switch the name of the id to 'machine_name' to be more ctools standard. db_change_field($table, $id, 'machine_name', array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, )); // Add a serial ID. db_add_field($table, $id, array( 'type' => 'serial', 'unsigned' => TRUE, 'not null' => TRUE, 'description' => 'Primary ID field for the table. Not used for anything except internal lookups.', // Do not export database-only keys. 'no export' => TRUE, ), array('primary key' => array($id)) ); } foreach (array('backup_migrate_sources', 'backup_migrate_destinations') as $table) { db_change_field($table, 'type', 'subtype', array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, )); } } /** * Update all schedules to use the built in cron if none is specified. */ function backup_migrate_update_7304() { db_query("UPDATE {backup_migrate_schedules} SET cron = 'builtin' WHERE cron = '0'"); } /** * Fix schema mismatch after upgrade. */ function backup_migrate_update_7305() { // Fix the 'machine_name' table fields. $field_spec = array( 'type' => 'varchar', 'length' => 255, 'not null' => TRUE, 'default' => '0', ); foreach (array( 'backup_migrate_profiles', 'backup_migrate_destinations', 'backup_migrate_sources', 'backup_migrate_schedules', ) as $table) { if (!db_field_exists($table, $machine_name)) { try { db_add_field($table, 'machine_name', $field_spec); } catch (\Exception $e) { db_change_field($table, 'machine_name', 'machine_name', $field_spec); } } else { db_change_field($table, 'machine_name', 'machine_name', $field_spec); } } // Fix the 'cron' table field. $field_spec = array( 'type' => 'varchar', 'length' => 32, 'not null' => TRUE, 'default' => 'builtin', ); if (!db_field_exists('backup_migrate_schedules', 'cron')) { try { db_add_field('backup_migrate_schedules', 'cron', $field_spec); } catch (\Exception $e) { db_change_field('backup_migrate_schedules', 'cron', 'cron', $field_spec); } } else { db_change_field('backup_migrate_schedules', 'cron', 'cron', $field_spec); } } /** * Leave a message to explain the mixup over the backup option. */ function backup_migrate_update_7306() { drupal_set_message(t('Please note that release 7.x-3.4 had a bug which caused all backups to be overwritten instead of having a timestamp added. Please review all backup settings to ensure they work as intended.'), 'warning'); } /** * 'backup_migrate_backup_memory_limit' vs 'backup_migrate_memory_limit'. */ function backup_migrate_update_7307() { $limit = variable_get('backup_migrate_backup_memory_limit'); if (!empty($limit)) { variable_set('backup_migrate_memory_limit', $limit); variable_del('backup_migrate_backup_memory_limit'); } }