Skip to content

Commit

Permalink
fix(fs): resolve paths correctly
Browse files Browse the repository at this point in the history
Should solve win32 issues

fix-compatability-bugs

fix-compatability-bugs
  • Loading branch information
trs committed May 6, 2017
1 parent 301ae11 commit a75d63d
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 45 deletions.
2 changes: 1 addition & 1 deletion src/commands/index.js
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,7 @@ class FtpCommands {
const handler = commandRegister.handler.bind(this.connection);
return when.try(handler, { log, command, previous_command: this.previousCommand })
.finally(() => {
this.previousCommand = _.cloneDeep(command);
this.previousCommand = _.clone(command);
});
}
}
Expand Down
2 changes: 1 addition & 1 deletion src/connection.js
Original file line number Diff line number Diff line change
Expand Up @@ -58,7 +58,7 @@ class FtpConnection {
return this.server.emit('login', {connection: this, username, password});
}
})
.then(({root = '/', cwd = '/', fs, blacklist = [], whitelist = []} = {}) => {
.then(({root, cwd, fs, blacklist = [], whitelist = []} = {}) => {
this.authenticated = true;
this.commands.blacklist = _.concat(this.commands.blacklist, blacklist);
this.commands.whitelist = _.concat(this.commands.whitelist, whitelist);
Expand Down
79 changes: 36 additions & 43 deletions src/fs.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,47 +8,40 @@ const fs = whenNode.liftAll(syncFs);
const errors = require('./errors');

class FileSystem {
constructor(connection, {
root = '/',
cwd = '/'
} = {}) {
constructor(connection, { root, cwd } = {}) {
this.connection = connection;
this.cwd = this._normalize(cwd);
this.root = this._normalize(root);
this.cwd = cwd || nodePath.sep;
this.root = root || process.cwd();
}

_normalize(path) {
return nodePath.normalize(path
.replace(/\\/g, '\/') // replaces \ with /
.replace(/\\\\/g, '\/') // replaces \\ with /
.replace(/\/\//g, '\/') // replaces // with /
);
}
_resolvePath(path = '') {
const isFromRoot = _.startsWith(path, '/') || _.startsWith(path, nodePath.sep);
const cwd = isFromRoot ? nodePath.sep : this.cwd || nodePath.sep;
const serverPath = nodePath.join(nodePath.sep, cwd, path);
const fsPath = nodePath.join(this.root, serverPath);

_resolvePath(path) {
const pathParts = {
root: this.root,
base: nodePath.join(this.cwd, this._normalize(path))
return {
serverPath,
fsPath
};
return nodePath.format(pathParts);
}

currentDirectory() {
return this.cwd;
}

get(fileName) {
const path = this._resolvePath(fileName);
return fs.stat(path)
const {fsPath} = this._resolvePath(fileName);
return fs.stat(fsPath)
.then(stat => _.set(stat, 'name', fileName));
}

list(path = '.') {
path = this._resolvePath(path);
return fs.readdir(path)
const {fsPath} = this._resolvePath(path);
return fs.readdir(fsPath)
.then(fileNames => {
return when.map(fileNames, fileName => {
const filePath = nodePath.join(path, fileName);
const filePath = nodePath.join(fsPath, fileName);
return fs.access(filePath, syncFs.constants.F_OK)
.then(() => {
return fs.stat(filePath)
Expand All @@ -61,60 +54,60 @@ class FileSystem {
}

chdir(path = '.') {
path = this._resolvePath(path);
return fs.stat(path)
const {fsPath, serverPath} = this._resolvePath(path);
return fs.stat(fsPath)
.tap(stat => {
if (!stat.isDirectory()) throw new errors.FileSystemError('Not a valid directory');
})
.then(() => {
this.cwd = path.substring(this.root.length) || '/';
this.cwd = serverPath;
return this.currentDirectory();
});
}

write(fileName, {append = false} = {}) {
const path = this._resolvePath(fileName);
const stream = syncFs.createWriteStream(path, {flags: !append ? 'w+' : 'a+'});
stream.on('error', () => fs.unlink(path));
const {fsPath} = this._resolvePath(fileName);
const stream = syncFs.createWriteStream(fsPath, {flags: !append ? 'w+' : 'a+'});
stream.on('error', () => fs.unlink(fsPath));
return stream;
}

read(fileName) {
const path = this._resolvePath(fileName);
return fs.stat(path)
const {fsPath} = this._resolvePath(fileName);
return fs.stat(fsPath)
.tap(stat => {
if (stat.isDirectory()) throw new errors.FileSystemError('Cannot read a directory');
})
.then(() => {
const stream = syncFs.createReadStream(path, {flags: 'r'});
const stream = syncFs.createReadStream(fsPath, {flags: 'r'});
return stream;
});
}

delete(path) {
path = this._resolvePath(path);
return fs.stat(path)
const {fsPath} = this._resolvePath(path);
return fs.stat(fsPath)
.then(stat => {
if (stat.isDirectory()) return fs.rmdir(path);
else return fs.unlink(path);
if (stat.isDirectory()) return fs.rmdir(fsPath);
else return fs.unlink(fsPath);
});
}

mkdir(path) {
path = this._resolvePath(path);
return fs.mkdir(path)
.then(() => path);
const {fsPath} = this._resolvePath(path);
return fs.mkdir(fsPath)
.then(() => fsPath);
}

rename(from, to) {
const fromPath = this._resolvePath(from);
const toPath = this._resolvePath(to);
const {fsPath: fromPath} = this._resolvePath(from);
const {fsPath: toPath} = this._resolvePath(to);
return fs.rename(fromPath, toPath);
}

chmod(path, mode) {
path = this._resolvePath(path);
return fs.chmod(path, mode);
const {fsPath} = this._resolvePath(path);
return fs.chmod(fsPath, mode);
}

getUniqueName() {
Expand Down
17 changes: 17 additions & 0 deletions test/start.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
require('dotenv').load();
const bunyan = require('bunyan');

const FtpServer = require('../src');

const log = bunyan.createLogger({name: 'test'});
log.level('info');
const server = new FtpServer('ftp://127.0.0.1:8880', {
log,
pasv_range: 8881
});
server.on('login', ({username, password}, resolve, reject) => {
console.log(username, password);
if (username === 'test' && password === 'test') resolve({ root: require('os').homedir() });
else reject('Bad username or password');
});
server.listen();

0 comments on commit a75d63d

Please sign in to comment.