diff options
-rw-r--r-- | net/data/ftp/dir-listing-ls-11 | 8 | ||||
-rw-r--r-- | net/data/ftp/dir-listing-ls-11.expected | 62 | ||||
-rw-r--r-- | net/data/ftp/dir-listing-ls-12 | 8 | ||||
-rw-r--r-- | net/data/ftp/dir-listing-ls-12.expected | 62 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_buffer_unittest.cc | 2 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_parser_ls.cc | 53 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_parser_ls.h | 5 | ||||
-rw-r--r-- | net/ftp/ftp_directory_listing_parser_ls_unittest.cc | 21 |
8 files changed, 204 insertions, 17 deletions
diff --git a/net/data/ftp/dir-listing-ls-11 b/net/data/ftp/dir-listing-ls-11 new file mode 100644 index 0000000..f81fda6 --- /dev/null +++ b/net/data/ftp/dir-listing-ls-11 @@ -0,0 +1,8 @@ +total 14 +drwxr-xr-x 2 other 512 Feb 25 2009 beid +lrwxrwxrwx 1 bin 9 May 1 2007 bin -> ./usr/bin +d--x--x--x 2 sys 512 May 1 2007 dev +d--x--x--x 5 sys 512 May 1 2007 etc +drwxr-xr-x 2 sys 512 Mar 27 2009 pub +drwxr-xr-x 3 other 512 Apr 11 2007 tigerd1 +d--x--x--x 6 sys 512 May 1 2007 usr diff --git a/net/data/ftp/dir-listing-ls-11.expected b/net/data/ftp/dir-listing-ls-11.expected new file mode 100644 index 0000000..82f1a9d --- /dev/null +++ b/net/data/ftp/dir-listing-ls-11.expected @@ -0,0 +1,62 @@ +d +beid +-1 +2009 +2 +25 +0 +0 + +l +bin +-1 +2007 +5 +1 +0 +0 + +d +dev +-1 +2007 +5 +1 +0 +0 + +d +etc +-1 +2007 +5 +1 +0 +0 + +d +pub +-1 +2009 +3 +27 +0 +0 + +d +tigerd1 +-1 +2007 +4 +11 +0 +0 + +d +usr +-1 +2007 +5 +1 +0 +0 diff --git a/net/data/ftp/dir-listing-ls-12 b/net/data/ftp/dir-listing-ls-12 new file mode 100644 index 0000000..7eee0bd --- /dev/null +++ b/net/data/ftp/dir-listing-ls-12 @@ -0,0 +1,8 @@ +total 14 +lrwxrwxrwx 1 other 7 Sep 1 2005 bin -> usr/bin +dr-xr-xr-x 2 other 512 Aug 9 2004 dev +dr-xr-xr-x 2 other 512 Sep 28 2006 etc +drwxr-xr-x 2 other 512 Sep 28 2006 msgs +drwxr-xr-x 53 other 1024 Jun 30 09:52 pub +dr-xr-xr-x 5 other 512 Aug 9 2004 usr +drwxr-xr-x 2 other 512 Aug 9 2004 var diff --git a/net/data/ftp/dir-listing-ls-12.expected b/net/data/ftp/dir-listing-ls-12.expected new file mode 100644 index 0000000..761f7f4 --- /dev/null +++ b/net/data/ftp/dir-listing-ls-12.expected @@ -0,0 +1,62 @@ +l +bin +-1 +2005 +9 +1 +0 +0 + +d +dev +-1 +2004 +8 +9 +0 +0 + +d +etc +-1 +2006 +9 +28 +0 +0 + +d +msgs +-1 +2006 +9 +28 +0 +0 + +d +pub +-1 +current +6 +30 +9 +52 + +d +usr +-1 +2004 +8 +9 +0 +0 + +d +var +-1 +2004 +8 +9 +0 +0 diff --git a/net/ftp/ftp_directory_listing_buffer_unittest.cc b/net/ftp/ftp_directory_listing_buffer_unittest.cc index cf107b9..559256e 100644 --- a/net/ftp/ftp_directory_listing_buffer_unittest.cc +++ b/net/ftp/ftp_directory_listing_buffer_unittest.cc @@ -28,6 +28,8 @@ TEST(FtpDirectoryListingBufferTest, Parse) { "dir-listing-ls-8", "dir-listing-ls-9", "dir-listing-ls-10", + "dir-listing-ls-11", + "dir-listing-ls-12", "dir-listing-netware-1", "dir-listing-netware-2", "dir-listing-vms-1", diff --git a/net/ftp/ftp_directory_listing_parser_ls.cc b/net/ftp/ftp_directory_listing_parser_ls.cc index 64feeed..cc09ca0 100644 --- a/net/ftp/ftp_directory_listing_parser_ls.cc +++ b/net/ftp/ftp_directory_listing_parser_ls.cc @@ -57,27 +57,49 @@ string16 GetStringPartAfterColumns(const string16& text, int columns) { return result; } +bool DetectColumnOffset(const std::vector<string16>& columns, int* offset) { + base::Time time; + + if (columns.size() >= 8 && + net::FtpUtil::LsDateListingToTime(columns[5], columns[6], columns[7], + &time)) { + // Standard listing, exactly like ls -l. + *offset = 1; + return true; + } + + if (columns.size() >= 7 && + net::FtpUtil::LsDateListingToTime(columns[4], columns[5], columns[6], + &time)) { + // wu-ftpd listing, no "number of links" column. + *offset = 0; + return true; + } + + // Unrecognized listing style. + return false; +} + } // namespace namespace net { FtpDirectoryListingParserLs::FtpDirectoryListingParserLs() : received_nonempty_line_(false), - received_total_line_(false) { + received_total_line_(false), + column_offset_(-1) { } bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) { + std::vector<string16> columns; + SplitString(CollapseWhitespace(line, false), ' ', &columns); + if (line.empty() && !received_nonempty_line_) { // Allow empty lines only at the beginning of the listing. For example VMS // systems in Unix emulation mode add an empty line before the first listing // entry. return true; } - received_nonempty_line_ = true; - - std::vector<string16> columns; - SplitString(CollapseWhitespace(line, false), ' ', &columns); - // Some FTP servers put a "total n" line at the beginning of the listing // (n is an integer). Allow such a line, but only once, and only if it's // the first non-empty line. Do not match the word exactly, because it may be @@ -94,11 +116,14 @@ bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) { return true; } + if (!received_nonempty_line_ && !DetectColumnOffset(columns, &column_offset_)) + return false; + received_nonempty_line_ = true; // We may receive file names containing spaces, which can make the number of // columns arbitrarily large. We will handle that later. For now just make // sure we have all the columns that should normally be there. - if (columns.size() < 9) + if (columns.size() < 8U + column_offset_) return false; if (!LooksLikeUnixPermissionsListing(columns[0])) @@ -113,25 +138,21 @@ bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) { entry.type = FtpDirectoryListingEntry::FILE; } - int number_of_links; - if (!StringToInt(columns[1], &number_of_links)) - return false; - if (number_of_links < 0) - return false; - - if (!StringToInt64(columns[4], &entry.size)) + if (!StringToInt64(columns[3 + column_offset_], &entry.size)) return false; if (entry.size < 0) return false; if (entry.type != FtpDirectoryListingEntry::FILE) entry.size = -1; - if (!FtpUtil::LsDateListingToTime(columns[5], columns[6], columns[7], + if (!FtpUtil::LsDateListingToTime(columns[4 + column_offset_], + columns[5 + column_offset_], + columns[6 + column_offset_], &entry.last_modified)) { return false; } - entry.name = GetStringPartAfterColumns(line, 8); + entry.name = GetStringPartAfterColumns(line, 7 + column_offset_); if (entry.type == FtpDirectoryListingEntry::SYMLINK) { string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> ")); if (pos == string16::npos) diff --git a/net/ftp/ftp_directory_listing_parser_ls.h b/net/ftp/ftp_directory_listing_parser_ls.h index 3fd0d32..50e0a1f 100644 --- a/net/ftp/ftp_directory_listing_parser_ls.h +++ b/net/ftp/ftp_directory_listing_parser_ls.h @@ -30,6 +30,11 @@ class FtpDirectoryListingParserLs : public FtpDirectoryListingParser { // integer. Only one such header is allowed per listing. bool received_total_line_; + // There is a variant of the listing served by wu-ftpd which doesn't contain + // the "number of links" column (the second column in a "standard" ls -l + // listing). Store an offset to reference later columns. + int column_offset_; + std::queue<FtpDirectoryListingEntry> entries_; DISALLOW_COPY_AND_ASSIGN(FtpDirectoryListingParserLs); diff --git a/net/ftp/ftp_directory_listing_parser_ls_unittest.cc b/net/ftp/ftp_directory_listing_parser_ls_unittest.cc index a58b839..f0ec455 100644 --- a/net/ftp/ftp_directory_listing_parser_ls_unittest.cc +++ b/net/ftp/ftp_directory_listing_parser_ls_unittest.cc @@ -40,6 +40,20 @@ TEST_F(FtpDirectoryListingParserLsTest, Good) { { "-rw-r--r-- 1 2 3 3447432 May 18 2009 Foo - Manual.pdf", net::FtpDirectoryListingEntry::FILE, "Foo - Manual.pdf", 3447432, 2009, 5, 18, 0, 0 }, + + // Tests for the wu-ftpd variant: + { "drwxr-xr-x 2 sys 512 Mar 27 2009 pub", + net::FtpDirectoryListingEntry::DIRECTORY, "pub", -1, + 2009, 3, 27, 0, 0 }, + { "lrwxrwxrwx 0 0 26 Sep 18 2008 pub -> vol/1/.CLUSTER/var_ftp/pub", + net::FtpDirectoryListingEntry::SYMLINK, "pub", -1, + 2008, 9, 18, 0, 0 }, + { "drwxr-xr-x (?) (?) 4096 Apr 8 2007 jigdo", + net::FtpDirectoryListingEntry::DIRECTORY, "jigdo", -1, + 2007, 4, 8, 0, 0 }, + { "-rw-r--r-- 2 3 3447432 May 18 2009 Foo - Manual.pdf", + net::FtpDirectoryListingEntry::FILE, "Foo - Manual.pdf", 3447432, + 2009, 5, 18, 0, 0 }, }; for (size_t i = 0; i < arraysize(good_cases); i++) { SCOPED_TRACE(StringPrintf("Test[%" PRIuS "]: %s", i, good_cases[i].input)); @@ -52,11 +66,16 @@ TEST_F(FtpDirectoryListingParserLsTest, Good) { TEST_F(FtpDirectoryListingParserLsTest, Bad) { const char* bad_cases[] = { "garbage", + "-rw-r--r-- ftp ftp", + "-rw-r--rgb ftp ftp 528 Nov 01 2007 README", + "-rw-rgbr-- ftp ftp 528 Nov 01 2007 README", + "qrwwr--r-- ftp ftp 528 Nov 01 2007 README", + "-rw-r--r-- ftp ftp -528 Nov 01 2007 README", + "-rw-r--r-- ftp ftp 528 Foo 01 2007 README", "-rw-r--r-- 1 ftp ftp", "-rw-r--rgb 1 ftp ftp 528 Nov 01 2007 README", "-rw-rgbr-- 1 ftp ftp 528 Nov 01 2007 README", "qrwwr--r-- 1 ftp ftp 528 Nov 01 2007 README", - "-rw-r--r-- -1 ftp ftp 528 Nov 01 2007 README", "-rw-r--r-- 1 ftp ftp -528 Nov 01 2007 README", "-rw-r--r-- 1 ftp ftp 528 Foo 01 2007 README", }; |