诸暨麻将添加redis
您最多选择25个主题 主题必须以字母或数字开头,可以包含连字符 (-),并且长度不得超过35个字符
 
 
 
 
 
 

508 行
18 KiB

  1. // Protocol Buffers - Google's data interchange format
  2. // Copyright 2008 Google Inc. All rights reserved.
  3. // https://developers.google.com/protocol-buffers/
  4. //
  5. // Redistribution and use in source and binary forms, with or without
  6. // modification, are permitted provided that the following conditions are
  7. // met:
  8. //
  9. // * Redistributions of source code must retain the above copyright
  10. // notice, this list of conditions and the following disclaimer.
  11. // * Redistributions in binary form must reproduce the above
  12. // copyright notice, this list of conditions and the following disclaimer
  13. // in the documentation and/or other materials provided with the
  14. // distribution.
  15. // * Neither the name of Google Inc. nor the names of its
  16. // contributors may be used to endorse or promote products derived from
  17. // this software without specific prior written permission.
  18. //
  19. // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
  20. // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
  21. // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
  22. // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
  23. // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
  24. // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
  25. // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  26. // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  27. // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  28. // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  29. // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  30. // Author: kenton@google.com (Kenton Varda)
  31. // Based on original Protocol Buffers design by
  32. // Sanjay Ghemawat, Jeff Dean, and others.
  33. #ifdef _MSC_VER
  34. #include <direct.h>
  35. #else
  36. #include <unistd.h>
  37. #endif
  38. #include <errno.h>
  39. #include <fcntl.h>
  40. #include <sys/stat.h>
  41. #include <sys/types.h>
  42. #include <algorithm>
  43. #include <memory>
  44. #include <google/protobuf/compiler/importer.h>
  45. #include <google/protobuf/compiler/parser.h>
  46. #include <google/protobuf/io/tokenizer.h>
  47. #include <google/protobuf/io/zero_copy_stream_impl.h>
  48. #include <google/protobuf/stubs/strutil.h>
  49. #include <google/protobuf/io/io_win32.h>
  50. #ifdef _WIN32
  51. #include <ctype.h>
  52. #endif
  53. namespace google {
  54. namespace protobuf {
  55. namespace compiler {
  56. #ifdef _WIN32
  57. // DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
  58. // them like we do below.
  59. using google::protobuf::io::win32::access;
  60. using google::protobuf::io::win32::open;
  61. #endif
  62. // Returns true if the text looks like a Windows-style absolute path, starting
  63. // with a drive letter. Example: "C:\foo". TODO(kenton): Share this with
  64. // copy in command_line_interface.cc?
  65. static bool IsWindowsAbsolutePath(const std::string& text) {
  66. #if defined(_WIN32) || defined(__CYGWIN__)
  67. return text.size() >= 3 && text[1] == ':' && isalpha(text[0]) &&
  68. (text[2] == '/' || text[2] == '\\') && text.find_last_of(':') == 1;
  69. #else
  70. return false;
  71. #endif
  72. }
  73. MultiFileErrorCollector::~MultiFileErrorCollector() {}
  74. // This class serves two purposes:
  75. // - It implements the ErrorCollector interface (used by Tokenizer and Parser)
  76. // in terms of MultiFileErrorCollector, using a particular filename.
  77. // - It lets us check if any errors have occurred.
  78. class SourceTreeDescriptorDatabase::SingleFileErrorCollector
  79. : public io::ErrorCollector {
  80. public:
  81. SingleFileErrorCollector(const std::string& filename,
  82. MultiFileErrorCollector* multi_file_error_collector)
  83. : filename_(filename),
  84. multi_file_error_collector_(multi_file_error_collector),
  85. had_errors_(false) {}
  86. ~SingleFileErrorCollector() {}
  87. bool had_errors() { return had_errors_; }
  88. // implements ErrorCollector ---------------------------------------
  89. void AddError(int line, int column, const std::string& message) override {
  90. if (multi_file_error_collector_ != NULL) {
  91. multi_file_error_collector_->AddError(filename_, line, column, message);
  92. }
  93. had_errors_ = true;
  94. }
  95. private:
  96. std::string filename_;
  97. MultiFileErrorCollector* multi_file_error_collector_;
  98. bool had_errors_;
  99. };
  100. // ===================================================================
  101. SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
  102. SourceTree* source_tree)
  103. : source_tree_(source_tree),
  104. fallback_database_(nullptr),
  105. error_collector_(nullptr),
  106. using_validation_error_collector_(false),
  107. validation_error_collector_(this) {}
  108. SourceTreeDescriptorDatabase::SourceTreeDescriptorDatabase(
  109. SourceTree* source_tree, DescriptorDatabase* fallback_database)
  110. : source_tree_(source_tree),
  111. fallback_database_(fallback_database),
  112. error_collector_(nullptr),
  113. using_validation_error_collector_(false),
  114. validation_error_collector_(this) {}
  115. SourceTreeDescriptorDatabase::~SourceTreeDescriptorDatabase() {}
  116. bool SourceTreeDescriptorDatabase::FindFileByName(const std::string& filename,
  117. FileDescriptorProto* output) {
  118. std::unique_ptr<io::ZeroCopyInputStream> input(source_tree_->Open(filename));
  119. if (input == NULL) {
  120. if (fallback_database_ != nullptr &&
  121. fallback_database_->FindFileByName(filename, output)) {
  122. return true;
  123. }
  124. if (error_collector_ != NULL) {
  125. error_collector_->AddError(filename, -1, 0,
  126. source_tree_->GetLastErrorMessage());
  127. }
  128. return false;
  129. }
  130. // Set up the tokenizer and parser.
  131. SingleFileErrorCollector file_error_collector(filename, error_collector_);
  132. io::Tokenizer tokenizer(input.get(), &file_error_collector);
  133. Parser parser;
  134. if (error_collector_ != NULL) {
  135. parser.RecordErrorsTo(&file_error_collector);
  136. }
  137. if (using_validation_error_collector_) {
  138. parser.RecordSourceLocationsTo(&source_locations_);
  139. }
  140. // Parse it.
  141. output->set_name(filename);
  142. return parser.Parse(&tokenizer, output) && !file_error_collector.had_errors();
  143. }
  144. bool SourceTreeDescriptorDatabase::FindFileContainingSymbol(
  145. const std::string& symbol_name, FileDescriptorProto* output) {
  146. return false;
  147. }
  148. bool SourceTreeDescriptorDatabase::FindFileContainingExtension(
  149. const std::string& containing_type, int field_number,
  150. FileDescriptorProto* output) {
  151. return false;
  152. }
  153. // -------------------------------------------------------------------
  154. SourceTreeDescriptorDatabase::ValidationErrorCollector::
  155. ValidationErrorCollector(SourceTreeDescriptorDatabase* owner)
  156. : owner_(owner) {}
  157. SourceTreeDescriptorDatabase::ValidationErrorCollector::
  158. ~ValidationErrorCollector() {}
  159. void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddError(
  160. const std::string& filename, const std::string& element_name,
  161. const Message* descriptor, ErrorLocation location,
  162. const std::string& message) {
  163. if (owner_->error_collector_ == NULL) return;
  164. int line, column;
  165. if (location == DescriptorPool::ErrorCollector::IMPORT) {
  166. owner_->source_locations_.FindImport(descriptor, element_name, &line,
  167. &column);
  168. } else {
  169. owner_->source_locations_.Find(descriptor, location, &line, &column);
  170. }
  171. owner_->error_collector_->AddError(filename, line, column, message);
  172. }
  173. void SourceTreeDescriptorDatabase::ValidationErrorCollector::AddWarning(
  174. const std::string& filename, const std::string& element_name,
  175. const Message* descriptor, ErrorLocation location,
  176. const std::string& message) {
  177. if (owner_->error_collector_ == NULL) return;
  178. int line, column;
  179. if (location == DescriptorPool::ErrorCollector::IMPORT) {
  180. owner_->source_locations_.FindImport(descriptor, element_name, &line,
  181. &column);
  182. } else {
  183. owner_->source_locations_.Find(descriptor, location, &line, &column);
  184. }
  185. owner_->error_collector_->AddWarning(filename, line, column, message);
  186. }
  187. // ===================================================================
  188. Importer::Importer(SourceTree* source_tree,
  189. MultiFileErrorCollector* error_collector)
  190. : database_(source_tree),
  191. pool_(&database_, database_.GetValidationErrorCollector()) {
  192. pool_.EnforceWeakDependencies(true);
  193. database_.RecordErrorsTo(error_collector);
  194. }
  195. Importer::~Importer() {}
  196. const FileDescriptor* Importer::Import(const std::string& filename) {
  197. return pool_.FindFileByName(filename);
  198. }
  199. void Importer::AddUnusedImportTrackFile(const std::string& file_name) {
  200. pool_.AddUnusedImportTrackFile(file_name);
  201. }
  202. void Importer::ClearUnusedImportTrackFiles() {
  203. pool_.ClearUnusedImportTrackFiles();
  204. }
  205. // ===================================================================
  206. SourceTree::~SourceTree() {}
  207. std::string SourceTree::GetLastErrorMessage() { return "File not found."; }
  208. DiskSourceTree::DiskSourceTree() {}
  209. DiskSourceTree::~DiskSourceTree() {}
  210. static inline char LastChar(const std::string& str) {
  211. return str[str.size() - 1];
  212. }
  213. // Given a path, returns an equivalent path with these changes:
  214. // - On Windows, any backslashes are replaced with forward slashes.
  215. // - Any instances of the directory "." are removed.
  216. // - Any consecutive '/'s are collapsed into a single slash.
  217. // Note that the resulting string may be empty.
  218. //
  219. // TODO(kenton): It would be nice to handle "..", e.g. so that we can figure
  220. // out that "foo/bar.proto" is inside "baz/../foo". However, if baz is a
  221. // symlink or doesn't exist, then things get complicated, and we can't
  222. // actually determine this without investigating the filesystem, probably
  223. // in non-portable ways. So, we punt.
  224. //
  225. // TODO(kenton): It would be nice to use realpath() here except that it
  226. // resolves symbolic links. This could cause problems if people place
  227. // symbolic links in their source tree. For example, if you executed:
  228. // protoc --proto_path=foo foo/bar/baz.proto
  229. // then if foo/bar is a symbolic link, foo/bar/baz.proto will canonicalize
  230. // to a path which does not appear to be under foo, and thus the compiler
  231. // will complain that baz.proto is not inside the --proto_path.
  232. static std::string CanonicalizePath(std::string path) {
  233. #ifdef _WIN32
  234. // The Win32 API accepts forward slashes as a path delimiter even though
  235. // backslashes are standard. Let's avoid confusion and use only forward
  236. // slashes.
  237. if (HasPrefixString(path, "\\\\")) {
  238. // Avoid converting two leading backslashes.
  239. path = "\\\\" + StringReplace(path.substr(2), "\\", "/", true);
  240. } else {
  241. path = StringReplace(path, "\\", "/", true);
  242. }
  243. #endif
  244. std::vector<std::string> canonical_parts;
  245. std::vector<std::string> parts = Split(
  246. path, "/", true); // Note: Removes empty parts.
  247. for (int i = 0; i < parts.size(); i++) {
  248. if (parts[i] == ".") {
  249. // Ignore.
  250. } else {
  251. canonical_parts.push_back(parts[i]);
  252. }
  253. }
  254. std::string result = Join(canonical_parts, "/");
  255. if (!path.empty() && path[0] == '/') {
  256. // Restore leading slash.
  257. result = '/' + result;
  258. }
  259. if (!path.empty() && LastChar(path) == '/' && !result.empty() &&
  260. LastChar(result) != '/') {
  261. // Restore trailing slash.
  262. result += '/';
  263. }
  264. return result;
  265. }
  266. static inline bool ContainsParentReference(const std::string& path) {
  267. return path == ".." || HasPrefixString(path, "../") ||
  268. HasSuffixString(path, "/..") || path.find("/../") != string::npos;
  269. }
  270. // Maps a file from an old location to a new one. Typically, old_prefix is
  271. // a virtual path and new_prefix is its corresponding disk path. Returns
  272. // false if the filename did not start with old_prefix, otherwise replaces
  273. // old_prefix with new_prefix and stores the result in *result. Examples:
  274. // string result;
  275. // assert(ApplyMapping("foo/bar", "", "baz", &result));
  276. // assert(result == "baz/foo/bar");
  277. //
  278. // assert(ApplyMapping("foo/bar", "foo", "baz", &result));
  279. // assert(result == "baz/bar");
  280. //
  281. // assert(ApplyMapping("foo", "foo", "bar", &result));
  282. // assert(result == "bar");
  283. //
  284. // assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
  285. // assert(!ApplyMapping("foo/bar", "baz", "qux", &result));
  286. // assert(!ApplyMapping("foobar", "foo", "baz", &result));
  287. static bool ApplyMapping(const std::string& filename,
  288. const std::string& old_prefix,
  289. const std::string& new_prefix, std::string* result) {
  290. if (old_prefix.empty()) {
  291. // old_prefix matches any relative path.
  292. if (ContainsParentReference(filename)) {
  293. // We do not allow the file name to use "..".
  294. return false;
  295. }
  296. if (HasPrefixString(filename, "/") || IsWindowsAbsolutePath(filename)) {
  297. // This is an absolute path, so it isn't matched by the empty string.
  298. return false;
  299. }
  300. result->assign(new_prefix);
  301. if (!result->empty()) result->push_back('/');
  302. result->append(filename);
  303. return true;
  304. } else if (HasPrefixString(filename, old_prefix)) {
  305. // old_prefix is a prefix of the filename. Is it the whole filename?
  306. if (filename.size() == old_prefix.size()) {
  307. // Yep, it's an exact match.
  308. *result = new_prefix;
  309. return true;
  310. } else {
  311. // Not an exact match. Is the next character a '/'? Otherwise,
  312. // this isn't actually a match at all. E.g. the prefix "foo/bar"
  313. // does not match the filename "foo/barbaz".
  314. int after_prefix_start = -1;
  315. if (filename[old_prefix.size()] == '/') {
  316. after_prefix_start = old_prefix.size() + 1;
  317. } else if (filename[old_prefix.size() - 1] == '/') {
  318. // old_prefix is never empty, and canonicalized paths never have
  319. // consecutive '/' characters.
  320. after_prefix_start = old_prefix.size();
  321. }
  322. if (after_prefix_start != -1) {
  323. // Yep. So the prefixes are directories and the filename is a file
  324. // inside them.
  325. std::string after_prefix = filename.substr(after_prefix_start);
  326. if (ContainsParentReference(after_prefix)) {
  327. // We do not allow the file name to use "..".
  328. return false;
  329. }
  330. result->assign(new_prefix);
  331. if (!result->empty()) result->push_back('/');
  332. result->append(after_prefix);
  333. return true;
  334. }
  335. }
  336. }
  337. return false;
  338. }
  339. void DiskSourceTree::MapPath(const std::string& virtual_path,
  340. const std::string& disk_path) {
  341. mappings_.push_back(Mapping(virtual_path, CanonicalizePath(disk_path)));
  342. }
  343. DiskSourceTree::DiskFileToVirtualFileResult
  344. DiskSourceTree::DiskFileToVirtualFile(const std::string& disk_file,
  345. std::string* virtual_file,
  346. std::string* shadowing_disk_file) {
  347. int mapping_index = -1;
  348. std::string canonical_disk_file = CanonicalizePath(disk_file);
  349. for (int i = 0; i < mappings_.size(); i++) {
  350. // Apply the mapping in reverse.
  351. if (ApplyMapping(canonical_disk_file, mappings_[i].disk_path,
  352. mappings_[i].virtual_path, virtual_file)) {
  353. // Success.
  354. mapping_index = i;
  355. break;
  356. }
  357. }
  358. if (mapping_index == -1) {
  359. return NO_MAPPING;
  360. }
  361. // Iterate through all mappings with higher precedence and verify that none
  362. // of them map this file to some other existing file.
  363. for (int i = 0; i < mapping_index; i++) {
  364. if (ApplyMapping(*virtual_file, mappings_[i].virtual_path,
  365. mappings_[i].disk_path, shadowing_disk_file)) {
  366. if (access(shadowing_disk_file->c_str(), F_OK) >= 0) {
  367. // File exists.
  368. return SHADOWED;
  369. }
  370. }
  371. }
  372. shadowing_disk_file->clear();
  373. // Verify that we can open the file. Note that this also has the side-effect
  374. // of verifying that we are not canonicalizing away any non-existent
  375. // directories.
  376. std::unique_ptr<io::ZeroCopyInputStream> stream(OpenDiskFile(disk_file));
  377. if (stream == NULL) {
  378. return CANNOT_OPEN;
  379. }
  380. return SUCCESS;
  381. }
  382. bool DiskSourceTree::VirtualFileToDiskFile(const std::string& virtual_file,
  383. std::string* disk_file) {
  384. std::unique_ptr<io::ZeroCopyInputStream> stream(
  385. OpenVirtualFile(virtual_file, disk_file));
  386. return stream != NULL;
  387. }
  388. io::ZeroCopyInputStream* DiskSourceTree::Open(const std::string& filename) {
  389. return OpenVirtualFile(filename, NULL);
  390. }
  391. std::string DiskSourceTree::GetLastErrorMessage() {
  392. return last_error_message_;
  393. }
  394. io::ZeroCopyInputStream* DiskSourceTree::OpenVirtualFile(
  395. const std::string& virtual_file, std::string* disk_file) {
  396. if (virtual_file != CanonicalizePath(virtual_file) ||
  397. ContainsParentReference(virtual_file)) {
  398. // We do not allow importing of paths containing things like ".." or
  399. // consecutive slashes since the compiler expects files to be uniquely
  400. // identified by file name.
  401. last_error_message_ =
  402. "Backslashes, consecutive slashes, \".\", or \"..\" "
  403. "are not allowed in the virtual path";
  404. return NULL;
  405. }
  406. for (int i = 0; i < mappings_.size(); i++) {
  407. std::string temp_disk_file;
  408. if (ApplyMapping(virtual_file, mappings_[i].virtual_path,
  409. mappings_[i].disk_path, &temp_disk_file)) {
  410. io::ZeroCopyInputStream* stream = OpenDiskFile(temp_disk_file);
  411. if (stream != NULL) {
  412. if (disk_file != NULL) {
  413. *disk_file = temp_disk_file;
  414. }
  415. return stream;
  416. }
  417. if (errno == EACCES) {
  418. // The file exists but is not readable.
  419. last_error_message_ =
  420. "Read access is denied for file: " + temp_disk_file;
  421. return NULL;
  422. }
  423. }
  424. }
  425. last_error_message_ = "File not found.";
  426. return NULL;
  427. }
  428. io::ZeroCopyInputStream* DiskSourceTree::OpenDiskFile(
  429. const std::string& filename) {
  430. int file_descriptor;
  431. do {
  432. file_descriptor = open(filename.c_str(), O_RDONLY);
  433. } while (file_descriptor < 0 && errno == EINTR);
  434. if (file_descriptor >= 0) {
  435. io::FileInputStream* result = new io::FileInputStream(file_descriptor);
  436. result->SetCloseOnDelete(true);
  437. return result;
  438. } else {
  439. return NULL;
  440. }
  441. }
  442. } // namespace compiler
  443. } // namespace protobuf
  444. } // namespace google