Index: net/ftp/ftp_directory_listing_parser_vms.cc |
diff --git a/net/ftp/ftp_directory_listing_parser_vms.cc b/net/ftp/ftp_directory_listing_parser_vms.cc |
deleted file mode 100644 |
index 05e687f1e239279cd2d5859cee149ba8040a84fe..0000000000000000000000000000000000000000 |
--- a/net/ftp/ftp_directory_listing_parser_vms.cc |
+++ /dev/null |
@@ -1,293 +0,0 @@ |
-// Copyright (c) 2012 The Chromium Authors. All rights reserved. |
-// Use of this source code is governed by a BSD-style license that can be |
-// found in the LICENSE file. |
- |
-#include "net/ftp/ftp_directory_listing_parser_vms.h" |
- |
-#include <vector> |
- |
-#include "base/strings/string_number_conversions.h" |
-#include "base/strings/string_split.h" |
-#include "base/strings/string_util.h" |
-#include "base/strings/utf_string_conversions.h" |
-#include "base/time/time.h" |
-#include "net/ftp/ftp_directory_listing_parser.h" |
-#include "net/ftp/ftp_util.h" |
- |
-namespace net { |
- |
-namespace { |
- |
-// Converts the filename component in listing to the filename we can display. |
-// Returns true on success. |
-bool ParseVmsFilename(const base::string16& raw_filename, |
- base::string16* parsed_filename, |
- FtpDirectoryListingEntry::Type* type) { |
- // On VMS, the files and directories are versioned. The version number is |
- // separated from the file name by a semicolon. Example: ANNOUNCE.TXT;2. |
- std::vector<base::string16> listing_parts; |
- base::SplitString(raw_filename, ';', &listing_parts); |
- if (listing_parts.size() != 2) |
- return false; |
- int version_number; |
- if (!base::StringToInt(listing_parts[1], &version_number)) |
- return false; |
- if (version_number < 0) |
- return false; |
- |
- // Even directories have extensions in the listings. Don't display extensions |
- // for directories; it's awkward for non-VMS users. Also, VMS is |
- // case-insensitive, but generally uses uppercase characters. This may look |
- // awkward, so we convert them to lower case. |
- std::vector<base::string16> filename_parts; |
- base::SplitString(listing_parts[0], '.', &filename_parts); |
- if (filename_parts.size() != 2) |
- return false; |
- if (EqualsASCII(filename_parts[1], "DIR")) { |
- *parsed_filename = base::StringToLowerASCII(filename_parts[0]); |
- *type = FtpDirectoryListingEntry::DIRECTORY; |
- } else { |
- *parsed_filename = base::StringToLowerASCII(listing_parts[0]); |
- *type = FtpDirectoryListingEntry::FILE; |
- } |
- return true; |
-} |
- |
-bool ParseVmsFilesize(const base::string16& input, int64* size) { |
- if (base::ContainsOnlyChars(input, base::ASCIIToUTF16("*"))) { |
- // Response consisting of asterisks means unknown size. |
- *size = -1; |
- return true; |
- } |
- |
- // VMS's directory listing gives us file size in blocks. We assume that |
- // the block size is 512 bytes. It doesn't give accurate file size, but is the |
- // best information we have. |
- const int kBlockSize = 512; |
- |
- if (base::StringToInt64(input, size)) { |
- if (*size < 0) |
- return false; |
- *size *= kBlockSize; |
- return true; |
- } |
- |
- std::vector<base::string16> parts; |
- base::SplitString(input, '/', &parts); |
- if (parts.size() != 2) |
- return false; |
- |
- int64 blocks_used, blocks_allocated; |
- if (!base::StringToInt64(parts[0], &blocks_used)) |
- return false; |
- if (!base::StringToInt64(parts[1], &blocks_allocated)) |
- return false; |
- if (blocks_used > blocks_allocated) |
- return false; |
- if (blocks_used < 0 || blocks_allocated < 0) |
- return false; |
- |
- *size = blocks_used * kBlockSize; |
- return true; |
-} |
- |
-bool LooksLikeVmsFileProtectionListingPart(const base::string16& input) { |
- if (input.length() > 4) |
- return false; |
- |
- // On VMS there are four different permission bits: Read, Write, Execute, |
- // and Delete. They appear in that order in the permission listing. |
- std::string pattern("RWED"); |
- base::string16 match(input); |
- while (!match.empty() && !pattern.empty()) { |
- if (match[0] == pattern[0]) |
- match = match.substr(1); |
- pattern = pattern.substr(1); |
- } |
- return match.empty(); |
-} |
- |
-bool LooksLikeVmsFileProtectionListing(const base::string16& input) { |
- if (input.length() < 2) |
- return false; |
- if (input[0] != '(' || input[input.length() - 1] != ')') |
- return false; |
- |
- // We expect four parts of the file protection listing: for System, Owner, |
- // Group, and World. |
- std::vector<base::string16> parts; |
- base::SplitString(input.substr(1, input.length() - 2), ',', &parts); |
- if (parts.size() != 4) |
- return false; |
- |
- return LooksLikeVmsFileProtectionListingPart(parts[0]) && |
- LooksLikeVmsFileProtectionListingPart(parts[1]) && |
- LooksLikeVmsFileProtectionListingPart(parts[2]) && |
- LooksLikeVmsFileProtectionListingPart(parts[3]); |
-} |
- |
-bool LooksLikeVmsUserIdentificationCode(const base::string16& input) { |
- if (input.length() < 2) |
- return false; |
- return input[0] == '[' && input[input.length() - 1] == ']'; |
-} |
- |
-bool LooksLikeVMSError(const base::string16& text) { |
- static const char* const kPermissionDeniedMessages[] = { |
- "%RMS-E-FNF", // File not found. |
- "%RMS-E-PRV", // Access denied. |
- "%SYSTEM-F-NOPRIV", |
- "privilege", |
- }; |
- |
- for (size_t i = 0; i < arraysize(kPermissionDeniedMessages); i++) { |
- if (text.find(base::ASCIIToUTF16(kPermissionDeniedMessages[i])) != |
- base::string16::npos) |
- return true; |
- } |
- |
- return false; |
-} |
- |
-bool VmsDateListingToTime(const std::vector<base::string16>& columns, |
- base::Time* time) { |
- DCHECK_EQ(4U, columns.size()); |
- |
- base::Time::Exploded time_exploded = { 0 }; |
- |
- // Date should be in format DD-MMM-YYYY. |
- std::vector<base::string16> date_parts; |
- base::SplitString(columns[2], '-', &date_parts); |
- if (date_parts.size() != 3) |
- return false; |
- if (!base::StringToInt(date_parts[0], &time_exploded.day_of_month)) |
- return false; |
- if (!FtpUtil::AbbreviatedMonthToNumber(date_parts[1], |
- &time_exploded.month)) |
- return false; |
- if (!base::StringToInt(date_parts[2], &time_exploded.year)) |
- return false; |
- |
- // Time can be in format HH:MM, HH:MM:SS, or HH:MM:SS.mm. Try to recognize the |
- // last type first. Do not parse the seconds, they will be ignored anyway. |
- base::string16 time_column(columns[3]); |
- if (time_column.length() == 11 && time_column[8] == '.') |
- time_column = time_column.substr(0, 8); |
- if (time_column.length() == 8 && time_column[5] == ':') |
- time_column = time_column.substr(0, 5); |
- if (time_column.length() != 5) |
- return false; |
- std::vector<base::string16> time_parts; |
- base::SplitString(time_column, ':', &time_parts); |
- if (time_parts.size() != 2) |
- return false; |
- if (!base::StringToInt(time_parts[0], &time_exploded.hour)) |
- return false; |
- if (!base::StringToInt(time_parts[1], &time_exploded.minute)) |
- return false; |
- |
- // We don't know the time zone of the server, so just use local time. |
- *time = base::Time::FromLocalExploded(time_exploded); |
- return true; |
-} |
- |
-} // namespace |
- |
-bool ParseFtpDirectoryListingVms( |
- const std::vector<base::string16>& lines, |
- std::vector<FtpDirectoryListingEntry>* entries) { |
- // The first non-empty line is the listing header. It often |
- // starts with "Directory ", but not always. We set a flag after |
- // seing the header. |
- bool seen_header = false; |
- |
- // Sometimes the listing doesn't end with a "Total" line, but |
- // it's only okay when it contains some errors (it's needed |
- // to distinguish it from "ls -l" format). |
- bool seen_error = false; |
- |
- for (size_t i = 0; i < lines.size(); i++) { |
- if (lines[i].empty()) |
- continue; |
- |
- if (StartsWith(lines[i], base::ASCIIToUTF16("Total of "), true)) { |
- // After the "total" line, all following lines must be empty. |
- for (size_t j = i + 1; j < lines.size(); j++) |
- if (!lines[j].empty()) |
- return false; |
- |
- return true; |
- } |
- |
- if (!seen_header) { |
- seen_header = true; |
- continue; |
- } |
- |
- if (LooksLikeVMSError(lines[i])) { |
- seen_error = true; |
- continue; |
- } |
- |
- std::vector<base::string16> columns; |
- base::SplitString(base::CollapseWhitespace(lines[i], false), ' ', &columns); |
- |
- if (columns.size() == 1) { |
- // There can be no continuation if the current line is the last one. |
- if (i == lines.size() - 1) |
- return false; |
- |
- // Skip the next line. |
- i++; |
- |
- // This refers to the continuation line. |
- if (LooksLikeVMSError(lines[i])) { |
- seen_error = true; |
- continue; |
- } |
- |
- // Join the current and next line and split them into columns. |
- base::SplitString( |
- base::CollapseWhitespace( |
- lines[i - 1] + base::ASCIIToUTF16(" ") + lines[i], false), |
- ' ', |
- &columns); |
- } |
- |
- FtpDirectoryListingEntry entry; |
- if (!ParseVmsFilename(columns[0], &entry.name, &entry.type)) |
- return false; |
- |
- // There are different variants of a VMS listing. Some display |
- // the protection listing and user identification code, some do not. |
- if (columns.size() == 6) { |
- if (!LooksLikeVmsFileProtectionListing(columns[5])) |
- return false; |
- if (!LooksLikeVmsUserIdentificationCode(columns[4])) |
- return false; |
- |
- // Drop the unneeded data, so that the following code can always expect |
- // just four columns. |
- columns.resize(4); |
- } |
- |
- if (columns.size() != 4) |
- return false; |
- |
- if (!ParseVmsFilesize(columns[1], &entry.size)) |
- return false; |
- if (entry.type != FtpDirectoryListingEntry::FILE) |
- entry.size = -1; |
- if (!VmsDateListingToTime(columns, &entry.last_modified)) |
- return false; |
- |
- entries->push_back(entry); |
- } |
- |
- // The only place where we return true is after receiving the "Total" line, |
- // that should be present in every VMS listing. Alternatively, if the listing |
- // contains error messages, it's OK not to have the "Total" line. |
- return seen_error; |
-} |
- |
-} // namespace net |