Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(254)

Side by Side Diff: net/ftp/ftp_directory_listing_parser_ls.cc

Issue 465035: Split FTP LIST parsing code into individual files for each listing style. (Closed)
Patch Set: fix Created 11 years ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View unified diff | Download patch
OLDNEW
(Empty)
1 // Copyright (c) 2009 The Chromium Authors. All rights reserved. Use of this
2 // source code is governed by a BSD-style license that can be found in the
3 // LICENSE file.
4
5 #include "net/ftp/ftp_directory_listing_parser_ls.h"
6
7 #include <vector>
8
9 #include "base/string_util.h"
10 #include "net/ftp/ftp_util.h"
11
12 namespace {
13
14 bool LooksLikeUnixPermission(const string16& text) {
15 if (text.length() != 3)
16 return false;
17
18 // Meaning of the flags:
19 // r - file is readable
20 // w - file is writable
21 // x - file is executable
22 // s or S - setuid/setgid bit set
23 // t or T - "sticky" bit set
24 return ((text[0] == 'r' || text[0] == '-') &&
25 (text[1] == 'w' || text[1] == '-') &&
26 (text[2] == 'x' || text[2] == 's' || text[2] == 'S' ||
27 text[2] == 't' || text[2] == 'T' || text[2] == '-'));
28 }
29
30 bool LooksLikeUnixPermissionsListing(const string16& text) {
31 if (text.length() != 10)
32 return false;
33
34 if (text[0] != 'b' && text[0] != 'c' && text[0] != 'd' &&
35 text[0] != 'l' && text[0] != 'p' && text[0] != 's' &&
36 text[0] != '-')
37 return false;
38
39 return (LooksLikeUnixPermission(text.substr(1, 3)) &&
40 LooksLikeUnixPermission(text.substr(4, 3)) &&
41 LooksLikeUnixPermission(text.substr(7, 3)));
42 }
43
44 string16 GetStringPartAfterColumns(const string16& text, int columns) {
45 DCHECK_LE(1, columns);
46 int columns_so_far = 0;
47 size_t last = 0;
48 for (size_t i = 1; i < text.length(); ++i) {
49 if (!isspace(text[i - 1]) && isspace(text[i])) {
50 last = i;
51 if (++columns_so_far == columns)
52 break;
53 }
54 }
55 string16 result(text.substr(last));
56 TrimWhitespace(result, TRIM_ALL, &result);
57 return result;
58 }
59
60 bool UnixDateListingToTime(const std::vector<string16>& columns,
61 base::Time* time) {
62 DCHECK_LE(9U, columns.size());
63
64 base::Time::Exploded time_exploded = { 0 };
65
66 if (!net::FtpUtil::ThreeLetterMonthToNumber(columns[5], &time_exploded.month))
67 return false;
68
69 if (!StringToInt(columns[6], &time_exploded.day_of_month))
70 return false;
71
72 if (!StringToInt(columns[7], &time_exploded.year)) {
73 // Maybe it's time. Does it look like time (MM:HH)?
74 if (columns[7].length() != 5 || columns[7][2] != ':')
75 return false;
76
77 if (!StringToInt(columns[7].substr(0, 2), &time_exploded.hour))
78 return false;
79
80 if (!StringToInt(columns[7].substr(3, 2), &time_exploded.minute))
81 return false;
82
83 // Use current year.
84 base::Time::Exploded now_exploded;
85 base::Time::Now().LocalExplode(&now_exploded);
86 time_exploded.year = now_exploded.year;
87 }
88
89 // We don't know the time zone of the server, so just use local time.
90 *time = base::Time::FromLocalExploded(time_exploded);
91 return true;
92 }
93
94 } // namespace
95
96 namespace net {
97
98 FtpDirectoryListingParserLs::FtpDirectoryListingParserLs()
99 : received_nonempty_line_(false) {
100 }
101
102 bool FtpDirectoryListingParserLs::ConsumeLine(const string16& line) {
103 if (StartsWith(line, ASCIIToUTF16("total "), true) ||
104 StartsWith(line, ASCIIToUTF16("Gesamt "), true)) {
105 // Some FTP servers put a "total n" line at the beginning of the listing
106 // (n is an integer). Allow such a line, but only once, and only if it's
107 // the first non-empty line.
108 //
109 // Note: "Gesamt" is a German word for "total". The case is important here:
110 // for "ls -l" style listings, "total" will be lowercase, and Gesamt will be
111 // capitalized. This helps us distinguish that from a VMS-style listing,
112 // which would use "Total" (note the uppercase first letter).
113
114 if (received_nonempty_line_)
115 return false;
116
117 received_nonempty_line_ = true;
118 return true;
119 }
120 if (line.empty() && !received_nonempty_line_) {
121 // Allow empty lines only at the beginning of the listing. For example VMS
122 // systems in Unix emulation mode add an empty line before the first listing
123 // entry.
124 return true;
125 }
126 received_nonempty_line_ = true;
127
128 std::vector<string16> columns;
129 SplitString(CollapseWhitespace(line, false), ' ', &columns);
130
131 // We may receive file names containing spaces, which can make the number of
132 // columns arbitrarily large. We will handle that later. For now just make
133 // sure we have all the columns that should normally be there.
134 if (columns.size() < 9)
135 return false;
136
137 if (!LooksLikeUnixPermissionsListing(columns[0]))
138 return false;
139
140 FtpDirectoryListingEntry entry;
141 if (columns[0][0] == 'l') {
142 entry.type = FtpDirectoryListingEntry::SYMLINK;
143 } else if (columns[0][0] == 'd') {
144 entry.type = FtpDirectoryListingEntry::DIRECTORY;
145 } else {
146 entry.type = FtpDirectoryListingEntry::FILE;
147 }
148
149 int number_of_links;
150 if (!StringToInt(columns[1], &number_of_links))
151 return false;
152 if (number_of_links < 0)
153 return false;
154
155 if (!StringToInt64(columns[4], &entry.size))
156 return false;
157 if (entry.size < 0)
158 return false;
159 if (entry.type != FtpDirectoryListingEntry::FILE)
160 entry.size = -1;
161
162 if (!UnixDateListingToTime(columns, &entry.last_modified))
163 return false;
164
165 entry.name = GetStringPartAfterColumns(line, 8);
166 if (entry.type == FtpDirectoryListingEntry::SYMLINK) {
167 string16::size_type pos = entry.name.rfind(ASCIIToUTF16(" -> "));
168 if (pos == string16::npos)
169 return false;
170 entry.name = entry.name.substr(0, pos);
171 }
172
173 entries_.push(entry);
174 return true;
175 }
176
177 bool FtpDirectoryListingParserLs::OnEndOfInput() {
178 return true;
179 }
180
181 bool FtpDirectoryListingParserLs::EntryAvailable() const {
182 return !entries_.empty();
183 }
184
185 FtpDirectoryListingEntry FtpDirectoryListingParserLs::PopEntry() {
186 FtpDirectoryListingEntry entry = entries_.front();
187 entries_.pop();
188 return entry;
189 }
190
191 } // namespace net
OLDNEW
« no previous file with comments | « net/ftp/ftp_directory_listing_parser_ls.h ('k') | net/ftp/ftp_directory_listing_parser_ls_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698