-
Notifications
You must be signed in to change notification settings - Fork 0
/
restore.js
executable file
·148 lines (136 loc) · 6.41 KB
/
restore.js
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
#!/usr/bin/env node
const fs = require('fs');
const winston = require('winston');
const async = require('async');
const assert = require('assert');
const spawn = require('child_process').spawn;
const argv = require('minimist')(process.argv.slice(2), {boolean:'d'});
const path = require('path');
const config = require('./config');
const logger = new winston.Logger(config.logger.winston);
const kk = require('./kk');
if(argv.h) {
console.log(fs.readFileSync(__dirname+"/README.md").toString());
process.exit(0);
}
var _path = argv._[0];
if(!_path) {
//when we deprecate non-real path, we can just use process.cwd()
if(process.env.PWD) {
logger.info("file/dir path not specified - using PWD");
_path = process.env.PWD;
} else {
logger.error("file/dir path not specified and PWD is not set");
process.exit(2);
}
}
if(!path.isAbsolute(_path.toString())) {
//when we deprecate non-real path, we can just do rootdir = path.resolve(rootdir)
if(process.env.PWD) {
_path = process.env.PWD+'/'+_path;
logger.info("relative path specified. Using PWD:", _path);
} else {
logger.error("PWD not set.. please specify an absolute path");
process.exit(2);
}
}
if(argv.d) {
logger.info("Running in dry-run mode");
}
kk.testSync(run);
function run() {
require('./db').getdb((err, db)=>{
if(err) throw err;
//let's try finding as a file
let realpath = fs.realpathSync(_path);
db.get("SELECT path, max(mtime) as max_mtime, tarid FROM files WHERE (path = ? or path = ?) GROUP BY path", _path, realpath, function(err, file) {
if(err) {
if(err.code == "SQLITE_BUSY") return logger.error("Database locked. Archive process still running?");
throw err;
}
if(!file) {
//not archived, or it's directory - let's try as directory..
//append / to prevent picking up /dirA, /dirB, /dirC..
if(_path[_path.length-1] != '/') _path = _path+"/";
if(realpath[realpath.length-1] != '/') realpath = realpath+"/";
var files = [];
db.each("SELECT path, max(mtime) as max_mtime, tarid FROM files WHERE (path LIKE ? or path LIKE ?) GROUP BY path", [_path+"%", realpath+"%"], function(err, file) {
if(err) {
if(err.code == "SQLITE_BUSY") return logger.error("Database locked. Previous archive process still running?");
throw err;
}
files.push(file);
}, function() {
if(files.length == 0) {
logger.error(_path, "not in archive");
process.exit(1);
}
restore(files);
});
} else {
//it's a file! check for mtime
restore([file]);
}
});
function restore(files) {
async.eachSeries(files, function(file, next_file) {
fs.stat(file.path, (err, stats)=>{
if(err) {
if(argv.d) {
logger.info("need-to-restore", file.path);
return next_file();
} else {
//file doesn't exist
var hpss_path = config.hpss_path+"/"+file.tarid+".tar";
logger.info("restoring",file.path,"from",hpss_path);
logger.debug('htar', ['-x', '-v', '-m', '-p', '-f', hpss_path, file.path], {cwd: "/"});
var htar = spawn('htar', ['-x', '-v', '-m', '-p', '-f', hpss_path, file.path], {cwd: "/"});
if(htar.stdout) htar.stdout.on('data', (data)=>{
logger.debug(data.toString());
});
if(htar.stderr) htar.stderr.on('data', (data)=>{
var msg = data.toString();
//assuming we receive one line at a time..
if(msg == "Warning: \"Network Options\" section not found in HPSS.conf file\n") return;
if(msg == "HTAR: Removing leading `/' from absolute path names in the archive\n") return;
logger.error(msg);
});
htar.on('close', (code)=>{
if(code != 0) {
return next_file("htar -x failed with code:"+code);
} else {
//-m updates the modified time locally, so I need to update the mtime
fs.stat(file.path, (err, new_stats)=>{
if(err) return next_file(err);
logger.debug("successfully restored - now updating mtime in archive", file, new_stats.mtime.getTime());
db.run("UPDATE files SET mtime = ? WHERE path = ? and mtime = ?",
new_stats.mtime.getTime(), file.path, file.max_mtime);
return next_file();
});
}
});
}
} else {
//file already exist - check for mtime
var mtime = stats.mtime.getTime();
if(file.max_mtime < mtime) {
//"already exists, but file in archive is stale. You should rerun archive.");
logger.warn("modified (you should re-archive)", file.path);
return next_file();
} else {
//logger.debug("file", file.max_mtime, "mtime", mtime);
assert(file.max_mtime == mtime);
logger.info("up-to-date",file.path);
return next_file();
}
}
});
}, function(err) {
if(err) throw err;
db.close(function() {
//done
});
});
}
});
}