2013-06-24 21:07:12 +00:00
|
|
|
/**
|
|
|
|
* File system based on storage provider
|
|
|
|
*/
|
|
|
|
|
|
|
|
var fs = require('fs'),
|
|
|
|
path = require('path'),
|
|
|
|
async = require('async');
|
|
|
|
|
|
|
|
module.exports = FileSystemProvider;
|
|
|
|
|
|
|
|
function FileSystemProvider(options) {
|
|
|
|
options = options || {};
|
|
|
|
this.root = options.root;
|
|
|
|
var stat = fs.statSync(this.root);
|
|
|
|
if (!stat.isDirectory()) {
|
|
|
|
throw new Error('Invalid directory: ' + this.root);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
var namePattern = new RegExp('[^' + path.sep + '/]+');
|
|
|
|
|
|
|
|
function validateName(name, cb) {
|
|
|
|
if (!name) {
|
|
|
|
cb && process.nextTick(cb.bind(null, new Error('Invalid name: ' + name)));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
var match = namePattern.exec(name);
|
|
|
|
if (match && match.index === 0 && match[0].length === name.length) {
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
cb && process.nextTick(cb.bind(null, new Error('Invalid name: ' + name)));
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// Container related functions
|
|
|
|
FileSystemProvider.prototype.getContainers = function (cb) {
|
|
|
|
var self = this;
|
|
|
|
fs.readdir(self.root, function (err, files) {
|
|
|
|
var dirs = [];
|
|
|
|
var tasks = [];
|
|
|
|
files.forEach(function (f) {
|
|
|
|
tasks.push(fs.stat.bind(null, path.join(self.root, f)));
|
|
|
|
});
|
|
|
|
async.parallel(tasks, function (err, stats) {
|
|
|
|
if (err) {
|
|
|
|
cb && cb(err);
|
|
|
|
} else {
|
|
|
|
stats.forEach(function (stat, index) {
|
|
|
|
if (stat.isDirectory()) {
|
|
|
|
dirs.push(files[index]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
cb && cb(err, dirs);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSystemProvider.prototype.createContainer = function (options, cb) {
|
|
|
|
var name = options.name;
|
|
|
|
var mode = options.mode || 0777;
|
|
|
|
validateName(name, cb) && fs.mkdir(path.join(this.root, name), options, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSystemProvider.prototype.destroyContainer = function (containerName, cb) {
|
|
|
|
if(!validateName(containerName, cb)) return;
|
|
|
|
|
|
|
|
var dir = path.join(this.root, containerName);
|
|
|
|
fs.readdir(dir, function (err, files) {
|
|
|
|
var tasks = [];
|
|
|
|
files.forEach(function (f) {
|
2013-06-24 22:53:14 +00:00
|
|
|
tasks.push(fs.unlink.bind(null, path.join(dir, f)));
|
2013-06-24 21:07:12 +00:00
|
|
|
});
|
|
|
|
async.parallel(tasks, function (err) {
|
|
|
|
if (err) {
|
|
|
|
cb && cb(err);
|
|
|
|
} else {
|
|
|
|
fs.rmdir(dir, cb);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSystemProvider.prototype.getContainer = function (containerName, cb) {
|
|
|
|
if(!validateName(containerName, cb)) return;
|
|
|
|
var dir = path.join(this.root, containerName);
|
|
|
|
fs.stat(dir, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// File related functions
|
|
|
|
FileSystemProvider.prototype.upload = function (options, cb) {
|
|
|
|
var container = options.container;
|
|
|
|
if(!validateName(container, cb)) return;
|
|
|
|
var file = options.remote;
|
|
|
|
if(!validateName(file, cb)) return;
|
|
|
|
var filePath = path.join(this.root, container, file);
|
|
|
|
|
|
|
|
var fileOpts = {flags: 'w+',
|
|
|
|
encoding: null,
|
|
|
|
mode: 0666 };
|
|
|
|
|
|
|
|
return fs.createWriteStream(filePath, fileOpts);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSystemProvider.prototype.download = function (options, cb) {
|
|
|
|
var container = options.container;
|
|
|
|
if(!validateName(container, cb)) return;
|
|
|
|
var file = options.remote;
|
|
|
|
if(!validateName(file, cb)) return;
|
|
|
|
|
|
|
|
var filePath = path.join(this.root, container, file);
|
|
|
|
|
|
|
|
var fileOpts = {flags: 'r',
|
|
|
|
autoClose: true };
|
|
|
|
|
|
|
|
return fs.createReadStream(filePath, fileOpts);
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSystemProvider.prototype.getFiles = function (container, cb) {
|
|
|
|
if(!validateName(container, cb)) return;
|
|
|
|
var dir = path.join(this.root, container);
|
|
|
|
fs.readdir(dir, function (err, files) {
|
|
|
|
var dirs = [];
|
|
|
|
var tasks = [];
|
|
|
|
files.forEach(function (f) {
|
2013-06-24 22:53:14 +00:00
|
|
|
tasks.push(fs.stat.bind(null, path.join(dir, f)));
|
2013-06-24 21:07:12 +00:00
|
|
|
});
|
|
|
|
async.parallel(tasks, function (err, stats) {
|
|
|
|
if (err) {
|
|
|
|
cb && cb(err);
|
|
|
|
} else {
|
|
|
|
stats.forEach(function (stat, index) {
|
|
|
|
if (stat.isFile()) {
|
|
|
|
dirs.push(files[index]);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
cb && cb(err, dirs);
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSystemProvider.prototype.getFile = function (container, file, cb) {
|
|
|
|
if(!validateName(container, cb)) return;
|
|
|
|
if(!validateName(file, cb)) return;
|
|
|
|
var filePath = path.join(this.root, container, file);
|
|
|
|
fs.stat(filePath, cb);
|
|
|
|
}
|
|
|
|
|
|
|
|
FileSystemProvider.prototype.removeFile = function (container, file, cb) {
|
|
|
|
if(!validateName(container, cb)) return;
|
|
|
|
if(!validateName(file, cb)) return;
|
|
|
|
|
|
|
|
var filePath = path.join(this.root, container, file);
|
|
|
|
fs.unlink(filePath, cb);
|
|
|
|
}
|