Thanks to visit codestin.com
Credit goes to github.com

Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
46 changes: 23 additions & 23 deletions lib/FtpConnection.js
Original file line number Diff line number Diff line change
Expand Up @@ -486,46 +486,46 @@ FtpConnection.prototype._LIST = function(commandArg, detailed, cmd) {
// We're not doing a detailed listing, so we don't need to get username
// and group name.
fileInfos = files;
return finished();
return finish();
}

// Now we need to get username and group name for each file from user/group ids.
fileInfos = [];

var CONC = self.server.options.maxStatsAtOnce;
var j = 0;
for (var i = 0; i < files.length && i < CONC; ++i) {
handleFile(i);
var total = files.length;
for (var i = 0; i < CONC; ++i) {
handleFile();
}
j = --i;

function handleFile(ii) {
if (i >= files.length) {
return i === files.length + j ? finished() : null;
function handleFile() {
if (fileInfos.length === total) {
return finish();
}

self.server.getUsernameFromUid(files[ii].stats.uid, function(e1, uname) {
self.server.getGroupFromGid(files[ii].stats.gid, function(e2, gname) {
if (files.length === 0) {
return;
}

var file = files.shift();
self.server.getUsernameFromUid(file.stats.uid, function(e1, uname) {
self.server.getGroupFromGid(file.stats.gid, function(e2, gname) {
if (e1 || e2) {
self._logIf(LOG.WARN, 'Error getting user/group name for file: ' + util.inspect(e1 || e2));
fileInfos.push({
file: files[ii],
uname: null,
gname: null,
});
} else {
fileInfos.push({
file: files[ii],
uname: uname,
gname: gname,
});
uname = null;
gname = null;
}
handleFile(++i);
fileInfos.push({
file: file,
uname: uname,
gname: gname,
});
handleFile();
});
});
}

function finished() {
function finish() {
// Sort file names.
if (!self.server.options.dontSortFilenames) {
if (self.server.options.filenameSortMap !== false) {
Expand Down
4 changes: 2 additions & 2 deletions lib/FtpServer.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,10 +31,10 @@ function FtpServer(host, options) {
self.getRoot = options.getRoot;

self.getUsernameFromUid = options.getUsernameFromUid || function(uid, c) {
c(null, 'ftp');
process.nextTick(c, null, 'ftp');
};
self.getGroupFromGid = options.getGroupFromGid || function(gid, c) {
c(null, 'ftp');
process.nextTick(c, null, 'ftp');
};
self.debugging = options.logLevel || 0;
self.useWriteFile = options.useWriteFile;
Expand Down
41 changes: 19 additions & 22 deletions lib/glob.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,46 +10,43 @@ function setMaxStatsAtOnce(n) {
// unique directory to be listed. So this can be pretty simple.

function statList(fsm, list, callback) {
if (list.length === 0) {
return callback(null, []);
}

var stats = [];
var total = list.length;
var finished = false;
var stats = [];

for (var i = 0; i < CONC; ++i) {
handleFile();
}

var erroredOut = false;

function handleFile() {
if (erroredOut) {
return;
if (stats.length === total) {
return finish(null);
}

if (list.length === 0) {
if (stats.length === total) {
finished();
}
return;
}

var path = list.shift();
fsm.stat(path, function(err, st) {
if (err) {
erroredOut = true;
callback(err);
} else {
stats.push({
name: PathModule.basename(path),
stats: st,
});
handleFile();
return finish(err);
}

stats.push({
name: PathModule.basename(path),
stats: st,
});
handleFile();
});
}

function finished() {
callback(null, stats);
function finish(err) {
if (finished) {
return;
}
finished = true;
callback(err, stats);
}
}

Expand Down
2 changes: 1 addition & 1 deletion test/lib/common.js
Original file line number Diff line number Diff line change
Expand Up @@ -73,7 +73,7 @@ var common = module.exports = {
});
connection.on('command:pass', function(pass, success, failure) {
if (pass === customOptions.pass) {
success(username);
success(username, customOptions.fs);
} else {
failure();
}
Expand Down
197 changes: 133 additions & 64 deletions test/list.js
Original file line number Diff line number Diff line change
@@ -1,86 +1,155 @@
var common = require('./lib/common');
var fs = require('fs');

describe('LIST command', function() {
'use strict';

var client;
var server;

beforeEach(function(done) {
server = common.server();
client = common.client(done);
});
describe('regular cases', function() {

function unslashRgx(rgx) {
return String(rgx).replace(/^\/|\/$/g, '');
}

it('should return "-" as first character for files', function(done) {
client.list('/', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing, / data\d*\.txt$/);
listing.should.have.lengthOf(6);
listing[0].should.startWith('-');
done();
beforeEach(function(done) {
server = common.server();
client = common.client(done);
});
});

it('should return "d" as first character for directories', function(done) {
client.list('/', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing, / usr$/);
listing.should.have.lengthOf(1);
listing[0].should.startWith('d');
done();
function unslashRgx(rgx) {
return String(rgx).replace(/^\/|\/$/g, '');
}

it('should return "-" as first character for files', function(done) {
client.list('/', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing, / data\d*\.txt$/);
listing.should.have.lengthOf(6);
listing[0].should.startWith('-');
done();
});
});
});

it('should list files similar to ls -l', function(done) {
client.list('/usr', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing);
listing.should.have.lengthOf(1);
var lsLongRgx = [
/($# file modes: ___|)[d-]([r-][w-][x-]){3}/,
/($# ?�?�? inodes?: |)\d+/,
/($# owner name: ___|)\S+/,
/($# owner group: __|)\S+/,
/($# size in bytes: |)\d+/,
/($# month: ________|)[A-Z][a-z]{2}/,
/($# day of month: _|)\d{1,2}/,
/($# time or year: _|)([\d ]\d:|19|[2-9]\d)\d{2}/,
/($# file name: ____|)[\S\s]+/,
].map(unslashRgx).join('\\s+');
lsLongRgx = new RegExp(lsLongRgx, '');
var match = (lsLongRgx.exec(listing[0]) || [false]);
match[0].should.equal(listing[0]);
done();
it('should return "d" as first character for directories', function(done) {
client.list('/', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing, / usr$/);
listing.should.have.lengthOf(1);
listing[0].should.startWith('d');
done();
});
});
});

it('should list a single file', function(done) {
var filename = 'data.txt';
client.list('/' + filename, function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing, ' ' + filename);
listing.should.have.lengthOf(1);
listing[0].should.startWith('-');
done();
it('should list files similar to ls -l', function(done) {
client.list('/usr', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing);
listing.should.have.lengthOf(1);
var lsLongRgx = [
/($# file modes: ___|)[d-]([r-][w-][x-]){3}/,
/($# ?�?�? inodes?: |)\d+/,
/($# owner name: ___|)\S+/,
/($# owner group: __|)\S+/,
/($# size in bytes: |)\d+/,
/($# month: ________|)[A-Z][a-z]{2}/,
/($# day of month: _|)\d{1,2}/,
/($# time or year: _|)([\d ]\d:|19|[2-9]\d)\d{2}/,
/($# file name: ____|)[\S\s]+/,
].map(unslashRgx).join('\\s+');
lsLongRgx = new RegExp(lsLongRgx, '');
var match = (lsLongRgx.exec(listing[0]) || [false]);
match[0].should.equal(listing[0]);
done();
});
});
});

it('should list a subdirectory', function(done) {
client.list('/usr', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing);
listing.should.have.lengthOf(1);
listing[0].should.startWith('d');
listing[0].should.endWith(' local');
done();
it('should list a single file', function(done) {
var filename = 'data.txt';
client.list('/' + filename, function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing, ' ' + filename);
listing.should.have.lengthOf(1);
listing[0].should.startWith('-');
done();
});
});

it('should list a subdirectory', function(done) {
client.list('/usr', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing);
listing.should.have.lengthOf(1);
listing[0].should.startWith('d');
listing[0].should.endWith(' local');
done();
});
});

afterEach(function() {
server.close();
});
});

afterEach(function() {
server.close();
describe('corner case', function() {
'use strict';

var files;

beforeEach(function(done) {
server = common.server({
fs: {
stat: function(path, callback) {
process.nextTick(
callback,
undefined /* err */,
new fs.Stats(0,32768 /* file mode */,0,0,0,0,0,0,0,43 /* size */,0,0,0,0)
);
},
readdir: function(path, callback) {
process.nextTick(callback, undefined, files);
},
},
});
client = common.client(done);
});

it('supports directories without files', function(done) {
files = [];
client.list('/', function(error, listing) {
error.should.equal(false);
listing.should.equal('');
done();
});
});

it('supports directories with only a few files', function(done) {
files = ['a'];
client.list('/', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing);
listing.should.have.lengthOf(1);
done();
});
});

it('supports directories with many files', function(done) {
function ArrayWithStrings(n) {
return Array.apply(null, Array(n)).map(function(x, i) {
return i.toString();
});
}
files = ArrayWithStrings(6000);
client.list('/', function(error, listing) {
error.should.equal(false);
listing = common.splitResponseLines(listing);
listing.should.have.lengthOf(files.length);
done();
});
});

afterEach(function() {
server.close();
});
});


});