This source file includes following definitions.
- ParseVmsFilename
- ParseVmsFilesize
- LooksLikeVmsFileProtectionListingPart
- LooksLikeVmsFileProtectionListing
- LooksLikeVmsUserIdentificationCode
- LooksLikeVMSError
- VmsDateListingToTime
- ParseFtpDirectoryListingVms
#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 {
bool ParseVmsFilename(const base::string16& raw_filename,
base::string16* parsed_filename,
FtpDirectoryListingEntry::Type* type) {
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;
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 = StringToLowerASCII(filename_parts[0]);
*type = FtpDirectoryListingEntry::DIRECTORY;
} else {
*parsed_filename = StringToLowerASCII(listing_parts[0]);
*type = FtpDirectoryListingEntry::FILE;
}
return true;
}
bool ParseVmsFilesize(const base::string16& input, int64* size) {
if (base::ContainsOnlyChars(input, base::ASCIIToUTF16("*"))) {
*size = -1;
return true;
}
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;
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;
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* kPermissionDeniedMessages[] = {
"%RMS-E-FNF",
"%RMS-E-PRV",
"%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 };
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;
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;
*time = base::Time::FromLocalExploded(time_exploded);
return true;
}
}
bool ParseFtpDirectoryListingVms(
const std::vector<base::string16>& lines,
std::vector<FtpDirectoryListingEntry>* entries) {
bool seen_header = false;
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)) {
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) {
if (i == lines.size() - 1)
return false;
i++;
if (LooksLikeVMSError(lines[i])) {
seen_error = true;
continue;
}
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;
if (columns.size() == 6) {
if (!LooksLikeVmsFileProtectionListing(columns[5]))
return false;
if (!LooksLikeVmsUserIdentificationCode(columns[4]))
return false;
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);
}
return seen_error;
}
}