mirror of
https://github.com/atom/atom.git
synced 2026-04-06 03:02:13 -04:00
Create FileRecoveryService to restore corrupted files after a crash
This commit is contained in:
@@ -4,6 +4,7 @@ AtomProtocolHandler = require './atom-protocol-handler'
|
||||
AutoUpdateManager = require './auto-update-manager'
|
||||
StorageFolder = require '../storage-folder'
|
||||
Config = require '../config'
|
||||
FileRecoveryService = require './file-recovery-service'
|
||||
ipcHelpers = require '../ipc-helpers'
|
||||
{BrowserWindow, Menu, app, dialog, ipcMain, shell} = require 'electron'
|
||||
fs = require 'fs-plus'
|
||||
@@ -78,12 +79,14 @@ class AtomApplication
|
||||
@autoUpdateManager = new AutoUpdateManager(@version, options.test, @resourcePath, @config)
|
||||
@applicationMenu = new ApplicationMenu(@version, @autoUpdateManager)
|
||||
@atomProtocolHandler = new AtomProtocolHandler(@resourcePath, @safeMode)
|
||||
@fileRecoveryService = new FileRecoveryService(path.join(process.env.ATOM_HOME, "recovery"))
|
||||
|
||||
@listenForArgumentsFromNewProcess()
|
||||
@setupJavaScriptArguments()
|
||||
@handleEvents()
|
||||
@setupDockMenu()
|
||||
@storageFolder = new StorageFolder(process.env.ATOM_HOME)
|
||||
@fileRecoveryService.start()
|
||||
|
||||
if options.pathsToOpen?.length > 0 or options.urlsToOpen?.length > 0 or options.test
|
||||
@openWithOptions(options)
|
||||
|
||||
60
src/browser/file-recovery-service.js
Normal file
60
src/browser/file-recovery-service.js
Normal file
@@ -0,0 +1,60 @@
|
||||
'use babel'
|
||||
|
||||
import {ipcMain} from 'electron'
|
||||
import crypto from 'crypto'
|
||||
import Path from 'path'
|
||||
import fs from 'fs-plus'
|
||||
|
||||
export default class FileRecoveryService {
|
||||
constructor (recoveryDirectory) {
|
||||
this.recoveryDirectory = recoveryDirectory
|
||||
this.recoveryPathsByWindowAndFilePath = new WeakMap
|
||||
this.crashListeners = new WeakSet
|
||||
}
|
||||
|
||||
start () {
|
||||
this.willSavePathListener = ipcMain.on('will-save-path', this.willSavePath.bind(this))
|
||||
this.didSavePathListener = ipcMain.on('did-save-path', this.didSavePath.bind(this))
|
||||
}
|
||||
|
||||
willSavePath (event, path) {
|
||||
if (!fs.existsSync(path)) {
|
||||
// Unexisting files won't be truncated/overwritten, and so there's no data to be lost.
|
||||
return
|
||||
}
|
||||
|
||||
const window = event.sender
|
||||
const recoveryFileName = crypto.createHash('sha1').update(path + Date.now().toString(), 'utf8').digest('hex').substring(0, 10)
|
||||
const recoveryPath = Path.join(this.recoveryDirectory, recoveryFileName)
|
||||
fs.writeFileSync(recoveryPath, fs.readFileSync(path))
|
||||
|
||||
if (!this.recoveryPathsByWindowAndFilePath.has(window)) {
|
||||
this.recoveryPathsByWindowAndFilePath.set(window, new Map)
|
||||
}
|
||||
this.recoveryPathsByWindowAndFilePath.get(window).set(path, recoveryPath)
|
||||
|
||||
if (!this.crashListeners.has(window)) {
|
||||
window.on('crashed', () => this.recoverFilesForWindow(window))
|
||||
this.crashListeners.add(window)
|
||||
}
|
||||
}
|
||||
|
||||
didSavePath (event, path) {
|
||||
const recoveryPathsByFilePath = this.recoveryPathsByWindowAndFilePath.get(event.sender)
|
||||
if (recoveryPathsByFilePath.has(path)) {
|
||||
const recoveryPath = recoveryPathsByFilePath.get(path)
|
||||
fs.unlinkSync(recoveryPath)
|
||||
recoveryPathsByFilePath.delete(path)
|
||||
}
|
||||
}
|
||||
|
||||
recoverFilesForWindow (window) {
|
||||
const recoveryPathsByFilePath = this.recoveryPathsByWindowAndFilePath.get(window)
|
||||
for (let [filePath, recoveryPath] of recoveryPathsByFilePath) {
|
||||
fs.writeFileSync(filePath, fs.readFileSync(recoveryPath))
|
||||
fs.unlinkSync(recoveryPath)
|
||||
}
|
||||
|
||||
recoveryPathsByFilePath.clear()
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user