function Local_Retention($job)
 {
     global $wpdb;
     // Grab info on existing local storage
     $current = $wpdb->get_row('SELECT COUNT(*) AS gens, SUM(filesize) AS storage ' . 'FROM `' . $this->db_prefix . 'wponlinebackup_local` ' . 'WHERE locked = 0', ARRAY_A);
     if (is_null($current)) {
         return $this->DBError(__FILE__, __LINE__);
     }
     // Grab minimum generation count to keep
     $min_gens = $this->WPOnlineBackup->Get_Setting('local_min_gens');
     // Grab maximum size for local backup storage - it's in MiB so multiply to get bytes
     $max_storage = $this->WPOnlineBackup->Get_Setting('local_max_storage') * 1048576;
     if ($job['progress'] == 0) {
         // Log an event to show current storage amount
         $this->Log_Event(WPONLINEBACKUP_EVENT_INFORMATION, sprintf(_n('Local Backups contains %1$s generation with a total size of %2$s.', 'Local Backups contains %1$s generations with a total size of %2$s.', $current['gens'], 'wponlinebackup'), $current['gens'], WPOnlineBackup_Formatting::Fix_B($current['storage'], true)));
         $job['progress'] = 25;
         // Set the message
         $this->status['progress']['message'] = __('Performing retention...', 'wponlinebackup');
         // Prevent duplicate log entries
         $this->Tick(false, true);
     }
     if ($job['progress'] == 25) {
         // If we're storing min_gens or less, no retention needed
         // Also, if storage is not full or gone over, no retention needed
         if ($current['gens'] <= $min_gens || $current['storage'] <= $max_storage) {
             // Log that no retention was required and mark as complete
             $this->Log_Event(WPONLINEBACKUP_EVENT_INFORMATION, __('Retention is not required.', 'wponlinebackup'));
             $job['progress'] = 100;
             // Prevent duplicate log entries
             $this->Tick(false, true);
             return true;
         }
         $job['progress'] = 50;
     }
     if ($job['progress'] == 50) {
         // Start removing the oldest backups until we're within the threshold
         while (true) {
             // Grab oldest 5
             $result = $wpdb->get_results('SELECT filename, filesize ' . 'FROM `' . $this->db_prefix . 'wponlinebackup_local` ' . 'WHERE locked = 0 ' . 'ORDER BY creation_date ASC ' . 'LIMIT 5', ARRAY_A);
             if (count($result) == 0) {
                 break;
             }
             foreach ($result as $row) {
                 // Delete it - if it's not there assume deleted (user may have deleted manually)
                 if (!file_exists(WPONLINEBACKUP_LOCALBACKUPDIR . '/' . $row['filename']) || false !== @unlink(WPONLINEBACKUP_LOCALBACKUPDIR . '/' . $row['filename'])) {
                     // Drop from database
                     $esc_filename = $row['filename'];
                     $wpdb->escape_by_ref($esc_filename);
                     $wpdb->query('DELETE FROM `' . $this->db_prefix . 'wponlinebackup_local` ' . 'WHERE filename = \'' . $esc_filename . '\'');
                     $update = false;
                 } else {
                     $err = OBFW_Tidy_Exception();
                     // Error!
                     $this->Log_Event(WPONLINEBACKUP_EVENT_ERROR, sprintf(__('Failed to delete local backup %1$s: %2$s', 'wponlinebackup'), $row['filename'], $err));
                     // Mark as error occured so we can log a bit of info after retention completes
                     $job['delete_error'] = 1;
                     // Force update to prevent dupe messages
                     $update = true;
                 }
                 // Log how much we deleted - even if we failed so we don't remove backups we SHOULD be keeping
                 $job['deleted_gens']++;
                 $job['deleted_storage'] += $row['filesize'];
                 // If we've now dropped the storage enough, leave the loops
                 if ($current['gens'] - $job['deleted_gens'] <= $min_gens || $current['storage'] - $job['deleted_storage'] <= $max_storage) {
                     break 2;
                 }
                 $this->Tick(false, $update);
             }
         }
         $job['progress'] = 95;
         // Force an update so we don't need to loop again
         $this->Tick(false, true);
     }
     if ($job['delete_error']) {
         // Explain that retention might grow larger than normal
         $this->Log_Event(WPONLINEBACKUP_EVENT_WARNING, __('Errors were encountered trying to delete one or more Local Backups. Disk space used by Local Backups will be higher than configured until they can be successfully removed.', 'wponlinebackup'));
     }
     // Mark as complete and log retention completed
     $this->Log_Event(WPONLINEBACKUP_EVENT_INFORMATION, sprintf(_n('Retention completed; deleted %d file with a total size of %s.', 'Retention completed; deleted %d files with a total size of %s.', $job['deleted_gens'], 'wponlinebackup'), $job['deleted_gens'], WPOnlineBackup_Formatting::Fix_B($job['deleted_storage'], true)));
     $job['progress'] = 100;
     // Prevent duplicate log entries
     $this->Tick(false, true);
     return true;
 }
Example #2
0
 function Backup(&$bootstrap, &$stream, &$progress, &$job)
 {
     $this->bootstrap =& $bootstrap;
     $this->stream =& $stream;
     $this->progress =& $progress;
     $this->job =& $job;
     // Is the file open?
     if ($this->file === false) {
         // Open it
         if (false === ($this->file = @fopen(WPONLINEBACKUP_LOCALBACKUPDIR . '/' . $progress['config']['file'], 'rb'))) {
             $ret = OBFW_Tidy_Exception();
             return sprintf(__('Failed to open the encrypted backup file at %s: %s', 'wponlinebackup'), $progress['config']['file'], $ret);
         }
         // Seek - don't forget to seek past header if we've finished it also, since done_bytes only counts the size AFTER the header
         if (0 != @fseek($this->file, $job['done_bytes'] + $job['header_bytes'], SEEK_SET)) {
             $ret = OBFW_Exception();
             return sprintf(__('Failed to access the encrypted backup file at %s: %s', 'wponlinebackup'), $progress['config']['file'], $ret);
         }
     }
     if ($job['progress'] < 10) {
         $this->progress['message'] = __('Validating the provided encryption details...', 'wponlinebackup');
         // Force update to update the message
         $bootstrap->Tick(false, true);
         // Read the header
         if (true !== ($ret = $this->_Read_Header())) {
             if ($ret === false) {
                 return __('The encryption details provided were incorrect.', 'wponlinebackup');
             }
             return sprintf(__('Failed to validate the encryption details provided. The error was: %s', 'wponlinebackup'), $ret);
         }
         // If legacy we might not have a len, in which case it will be false
         if ($job['header']['len'] === false) {
             $bootstrap->Log_Event(WPONLINEBACKUP_EVENT_INFORMATION, __('Encryption details validated successfully.', 'wponlinebackup'));
         } else {
             $bootstrap->Log_Event(WPONLINEBACKUP_EVENT_INFORMATION, sprintf(__('Encryption details validated successfully. The total decrypted backup size will be %s.', 'wponlinebackup'), WPOnlineBackup_Formatting::Fix_B($job['header']['len'], true)));
         }
         $job['progress'] = 10;
         // Next message
         $this->progress['message'] = __('Decrypting...', 'wponlinebackup');
         // Force update to update the message again and to prevent duplicated events
         $bootstrap->Tick(false, true);
     }
     // Is decryption initialised?
     if ($this->cipher === false) {
         // Pass false to prevent key validation, which is already done during _Read_Header
         if (true !== ($ret = $this->_Load_Decryption_Cipher(false))) {
             return sprintf(__('Failed to initialise the decryption process. The error was: %s', 'wponlinebackup'), $ret);
         }
     }
     // Initialise hash
     if ($this->WPOnlineBackup->Get_Env('inc_hash_available')) {
         $this->hash_ctx = hash_init('crc32b');
     } else {
         $this->hash_ctx = false;
     }
     // Do we have a saved hash_ctx we can load?
     if (isset($job['saved_hash_ctx'])) {
         if ($job['saved_hash_ctx'] !== false) {
             if ($job['crc'] !== false) {
                 $job['crc'] = WPOnlineBackup_Functions::Combine_CRC32($job['crc'], $job['saved_hash_ctx'], $job['hash_len']);
             } else {
                 $job['crc'] = $job['saved_hash_ctx'];
             }
         }
         $job['saved_hash_ctx'] = false;
     }
     $job['hash_len'] = 0;
     if (true !== ($ret = $this->_Decryption_Loop())) {
         // False means CRC failure
         if ($ret === false) {
             return __('The file integrity check failed. The file may be corrupt or the encryption details validated but were actually incorrect (there is a small chance of this happening.)', 'wponlinebackup');
         }
         return sprintf(__('Decryption failed. The error was: %s', 'wponlinebackup'), $ret);
     }
     // Clean up cipher
     $this->_CleanUp_Cipher();
     // Completed!
     $job['progress'] = 100;
     $progress['rcount']++;
     $progress['rsize'] += $job['done_bytes'];
     $bootstrap->Log_Event(WPONLINEBACKUP_EVENT_INFORMATION, __('Decryption completed successfully.', 'wponlinebackup'));
     // Force update so no duplicate events
     $bootstrap->Tick(false, true);
     return true;
 }
 function Fetch_Stat($file)
 {
     if (($file_size = @filesize($file)) === false) {
         $ret = OBFW_Tidy_Exception();
         return OBFW_FOpen_Exception($file, $ret);
     }
     if (($mod_time = @filemtime($file)) === false) {
         $ret = OBFW_Tidy_Exception();
         return OBFW_FOpen_Exception($file, $ret);
     }
     return compact('file_size', 'mod_time');
 }
 function OBFW_FOpen_Exception($path, $original)
 {
     // We call this when we failed to call filesize or stat, because they simply return "stat failed" which is pretty useless
     // Calling fopen and getting the error from that will give us a better error, such as "permission denied"
     if (false === ($f = @fopen($path, 'rb'))) {
         return OBFW_Tidy_Exception();
     }
     // We opened successfully, which is odd, so just close and return the original exception
     @fclose($f);
     return $original;
 }
 function Add_Large_File($bin, $file, $path, &$size, $status)
 {
     // Open file
     if (!($fh = @fopen($path, 'rb'))) {
         $size = OBFW_Tidy_Exception();
         return true;
     }
     // Force compressor and writer to register temporary files
     $this->compressor->Register_Temps(true);
     $this->writer->Register_Temps(true);
     $size = 0;
     $zlen = 0;
     // Start the stream
     if (true !== ($ret = $this->Start_Stream($bin, $file, $size, $status))) {
         @fclose($fh);
         return $ret;
     }
     $writing = false;
     // Read each block, update crc and zlen and write data
     while (true) {
         // Read a block
         if (($data = @fread($fh, $this->WPOnlineBackup->Get_Setting('max_block_size'))) === false) {
             $size = OBFW_Tidy_Exception();
             @fclose($fh);
             // Restore compressor and writer
             $this->writer->Register_Temps(false);
             $this->compressor->Register_Temps(false);
             return true;
         }
         // Get length of data read
         $len = strlen($data);
         // Update size
         $size += $len;
         // Write to the stream
         if (($ret = $this->Write_Stream($data, $len)) !== true) {
             @fclose($fh);
             return $ret;
         }
         // End of file? End loop
         if (@feof($fh)) {
             break;
         }
     }
     // Close the file
     @fclose($fh);
     // End the stream
     if (true !== ($ret = $this->End_Stream())) {
         return $ret;
     }
     // Commit the stream
     if (true !== ($ret = $this->Commit_Stream())) {
         return $ret;
     }
     // Clean up the stream
     if (true !== ($ret = $this->CleanUp_Stream())) {
         return $ret;
     }
     // Restore compressor and writer
     $this->writer->Register_Temps(false);
     $this->compressor->Register_Temps(false);
     return true;
 }
 function _Delete_Local($filename)
 {
     global $wpdb;
     // Delete the file - if it isn't found, just display the backup page
     $esc_filename = $filename;
     $wpdb->escape_by_ref($esc_filename);
     $result = $wpdb->get_row('SELECT filename ' . 'FROM `' . $wpdb->prefix . 'wponlinebackup_local` ' . 'WHERE filename = \'' . $esc_filename . '\'', ARRAY_A);
     if (!is_null($result)) {
         if (file_exists(WPONLINEBACKUP_LOCALBACKUPDIR . '/' . $result['filename'])) {
             $ret = @unlink(WPONLINEBACKUP_LOCALBACKUPDIR . '/' . $result['filename']);
         } else {
             $ret = true;
         }
         if ($ret === true) {
             $wpdb->query('DELETE FROM `' . $wpdb->prefix . 'wponlinebackup_local` ' . 'WHERE filename = \'' . $result['filename'] . '\'');
             $this->Register_Messages(array(array('icon' => 'accept', 'text' => __('Deleted backup.', 'wponlinebackup'))));
         } else {
             $ret = OBFW_Tidy_Exception();
             $this->Register_Messages(array(array('icon' => 'error', 'text' => sprintf(__('Failed to delete the backup: %s', 'wponlinebackup'), $ret))));
         }
         return true;
     }
     return false;
 }