Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code

Delta Between Two Patch Sets: src/DefaultFileSystem.cpp

Issue 10518027: Don`t use stat() on Windows, use a Unicode-safe Windows function instead (Closed)
Left Patch Set: Created May 10, 2013, 3:09 p.m.
Right Patch Set: Addressed review comments Created May 17, 2013, 10:44 a.m.
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments.
Jump to:
Left: Side by side diff | Download
Right: Side by side diff | Download
« no previous file with change/comment | « include/AdblockPlus/FileSystem.h ('k') | no next file » | no next file with change/comment »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
LEFTRIGHT
1 /* 1 /*
2 * This file is part of Adblock Plus <http://adblockplus.org/>, 2 * This file is part of Adblock Plus <http://adblockplus.org/>,
3 * Copyright (C) 2006-2013 Eyeo GmbH 3 * Copyright (C) 2006-2013 Eyeo GmbH
4 * 4 *
5 * Adblock Plus is free software: you can redistribute it and/or modify 5 * Adblock Plus is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License version 3 as 6 * it under the terms of the GNU General Public License version 3 as
7 * published by the Free Software Foundation. 7 * published by the Free Software Foundation.
8 * 8 *
9 * Adblock Plus is distributed in the hope that it will be useful, 9 * Adblock Plus is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
(...skipping 28 matching lines...) Expand all
39 namespace 39 namespace
40 { 40 {
41 class RuntimeErrorWithErrno : public std::runtime_error 41 class RuntimeErrorWithErrno : public std::runtime_error
42 { 42 {
43 public: 43 public:
44 explicit RuntimeErrorWithErrno(const std::string& message) 44 explicit RuntimeErrorWithErrno(const std::string& message)
45 : std::runtime_error(message + " (" + strerror(errno) + ")") 45 : std::runtime_error(message + " (" + strerror(errno) + ")")
46 { 46 {
47 } 47 }
48 }; 48 };
49
50 #ifdef WIN32
51 // Paths need to be converted from UTF-8 to UTF-16 on Windows.
52 std::wstring NormalizePath(const std::string& path)
53 {
54 return Utils::ToUTF16String(path);
55 }
56
57 #define rename _wrename
58 #define remove _wremove
59 #else
60 // POSIX systems: assume that file system encoding is UTF-8 and just use the
61 // file paths as they are.
62 #define NormalizePath(path) (path)
63 #endif
49 } 64 }
50 65
51 std::tr1::shared_ptr<std::istream> 66 std::tr1::shared_ptr<std::istream>
52 DefaultFileSystem::Read(const std::string& path) const 67 DefaultFileSystem::Read(const std::string& path) const
53 { 68 {
54 return std::tr1::shared_ptr<std::istream>(new std::ifstream(path.c_str())); 69 return std::tr1::shared_ptr<std::istream>(new std::ifstream(NormalizePath(path ).c_str()));
55 } 70 }
56 71
57 void DefaultFileSystem::Write(const std::string& path, 72 void DefaultFileSystem::Write(const std::string& path,
58 std::tr1::shared_ptr<std::ostream> data) 73 std::tr1::shared_ptr<std::ostream> data)
59 { 74 {
60 std::ofstream file(path.c_str()); 75 std::ofstream file(NormalizePath(path).c_str());
61 file << Utils::Slurp(*data); 76 file << Utils::Slurp(*data);
62 } 77 }
63 78
64 void DefaultFileSystem::Move(const std::string& fromPath, 79 void DefaultFileSystem::Move(const std::string& fromPath,
65 const std::string& toPath) 80 const std::string& toPath)
66 { 81 {
67 if (rename(fromPath.c_str(), toPath.c_str())) 82 if (rename(NormalizePath(fromPath).c_str(), NormalizePath(toPath).c_str()))
68 throw RuntimeErrorWithErrno("Failed to move " + fromPath + " to " + toPath); 83 throw RuntimeErrorWithErrno("Failed to move " + fromPath + " to " + toPath);
69 } 84 }
70 85
71 void DefaultFileSystem::Remove(const std::string& path) 86 void DefaultFileSystem::Remove(const std::string& path)
72 { 87 {
73 if (remove(path.c_str())) 88 if (remove(NormalizePath(path).c_str()))
74 throw RuntimeErrorWithErrno("Failed to remove " + path); 89 throw RuntimeErrorWithErrno("Failed to remove " + path);
75 } 90 }
76 91
77 FileSystem::StatResult DefaultFileSystem::Stat(const std::string& path) const 92 FileSystem::StatResult DefaultFileSystem::Stat(const std::string& path) const
78 { 93 {
79 FileSystem::StatResult result; 94 FileSystem::StatResult result;
80 #ifdef WIN32 95 #ifdef WIN32
81 WIN32_FILE_ATTRIBUTE_DATA data; 96 WIN32_FILE_ATTRIBUTE_DATA data;
82 std::wstring wpath = Utils::ToUTF16String(path, path.length()); 97 if (!GetFileAttributesExW(NormalizePath(path).c_str(), GetFileExInfoStandard, &data))
83 if (!GetFileAttributesExW(wpath.c_str(), GetFileExInfoStandard, &data))
84 { 98 {
85 DWORD err = GetLastError(); 99 DWORD err = GetLastError();
86 if (err == ERROR_FILE_NOT_FOUND || ERROR_PATH_NOT_FOUND || ERROR_INVALID_DRI VE) 100 if (err == ERROR_FILE_NOT_FOUND ||
Felix Dahlke 2013/05/17 09:18:50 Shouldn't this be "err == ERROR_FILE_NOT_FOUND ||
101 err == ERROR_PATH_NOT_FOUND ||
102 err == ERROR_INVALID_DRIVE)
103 {
87 return result; 104 return result;
105 }
88 throw RuntimeErrorWithErrno("Unable to stat " + path); 106 throw RuntimeErrorWithErrno("Unable to stat " + path);
89 } 107 }
90 108
91 result.exists = true; 109 result.exists = true;
92 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) 110 if (data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
93 { 111 {
94 result.isFile = false; 112 result.isFile = false;
95 result.isDirectory = true; 113 result.isDirectory = true;
96 } 114 }
97 else 115 else
98 { 116 {
99 result.isFile = true; 117 result.isFile = true;
100 result.isDirectory = false; 118 result.isDirectory = false;
101 } 119 }
102 120
103 // See http://support.microsoft.com/kb/167296 on this conversion 121 // See http://support.microsoft.com/kb/167296 on this conversion
104 #define FILE_TIME_TO_UNIX_EPOCH_OFFSET 116444736000000000LL 122 #define FILE_TIME_TO_UNIX_EPOCH_OFFSET 116444736000000000LL
105 #define FILE_TIME_TO_MILLISECONDS_FACTOR 10000 123 #define FILE_TIME_TO_MILLISECONDS_FACTOR 10000
106 ULARGE_INTEGER time; 124 ULARGE_INTEGER time;
107 time.LowPart = data.ftLastWriteTime.dwLowDateTime; 125 time.LowPart = data.ftLastWriteTime.dwLowDateTime;
108 time.HighPart = data.ftLastWriteTime.dwHighDateTime; 126 time.HighPart = data.ftLastWriteTime.dwHighDateTime;
109 result.lastModified = (time.QuadPart - FILE_TIME_TO_UNIX_EPOCH_OFFSET) / 127 result.lastModified = (time.QuadPart - FILE_TIME_TO_UNIX_EPOCH_OFFSET) /
110 FILE_TIME_TO_MILLISECONDS_FACTOR; 128 FILE_TIME_TO_MILLISECONDS_FACTOR;
111 return result; 129 return result;
112 #else 130 #else
113 struct stat nativeStat; 131 struct stat nativeStat;
114 const int failure = stat(path.c_str(), &nativeStat); 132 const int failure = stat(NormalizePath(path).c_str(), &nativeStat);
115 if (failure) 133 if (failure)
116 { 134 {
117 if (errno == ENOENT) 135 if (errno == ENOENT)
118 return result; 136 return result;
119 throw RuntimeErrorWithErrno("Unable to stat " + path); 137 throw RuntimeErrorWithErrno("Unable to stat " + path);
120 } 138 }
121 result.exists = true; 139 result.exists = true;
122 result.isFile = S_ISREG(nativeStat.st_mode); 140 result.isFile = S_ISREG(nativeStat.st_mode);
123 result.isDirectory = S_ISDIR(nativeStat.st_mode); 141 result.isDirectory = S_ISDIR(nativeStat.st_mode);
124 142
125 /* 143 #define MSEC_IN_SEC 1000
126 * In order to get millisecond resolution for modification times, it's necessa ry to use the 'stat' structure defined in 144 #define NSEC_IN_MSEC 1000000
127 * POSIX 2008, which has 'struct timespec st_mtim' instead of 'time_t st_mtime '. Use "#define _POSIX_C_SOURCE 200809L" 145 // Note: _POSIX_C_SOURCE macro is defined automatically on Linux due to g++
128 * before the headers to invoke. The trouble is that not all systems may have this available, a category that includes 146 // defining _GNU_SOURCE macro. On OS X we still fall back to the "no
129 * MS Windows, and so we'll need multiple implementations. 147 // milliseconds" branch, it has st_mtimespec instead of st_mtim.
130 */ 148 #if _POSIX_C_SOURCE >= 200809L
131 result.lastModified = static_cast<int64_t>(nativeStat.st_mtime) * 1000; 149 result.lastModified = static_cast<int64_t>(nativeStat.st_mtim.tv_sec) * MSEC_I N_SEC
150 + static_cast<int64_t>(nativeStat.st_mtim.tv_nsec) / NSEC _IN_MSEC;
151 #else
152 result.lastModified = static_cast<int64_t>(nativeStat.st_mtime) * MSEC_IN_SEC;
153 #endif
132 return result; 154 return result;
133 #endif 155 #endif
134 } 156 }
135 157
136 std::string DefaultFileSystem::Resolve(const std::string& path) const 158 std::string DefaultFileSystem::Resolve(const std::string& path) const
137 { 159 {
138 if (basePath == "") 160 if (basePath == "")
139 { 161 {
140 return path; 162 return path;
141 } 163 }
142 else 164 else
143 { 165 {
144 #ifdef _WIN32 166 #ifdef _WIN32
145 if (PathIsRelative(Utils::ToUTF16String(path, path.length()).c_str())) 167 if (PathIsRelative(NormalizePath(path).c_str()))
146 #else 168 #else
147 if (path.length() && *path.begin() != PATH_SEPARATOR) 169 if (path.length() && *path.begin() != PATH_SEPARATOR)
148 #endif 170 #endif
149 { 171 {
150 return basePath + PATH_SEPARATOR + path; 172 return basePath + PATH_SEPARATOR + path;
151 } 173 }
152 else 174 else
153 { 175 {
154 return path; 176 return path;
155 } 177 }
156 } 178 }
157 } 179 }
158 180
159 void DefaultFileSystem::SetBasePath(const std::string& path) 181 void DefaultFileSystem::SetBasePath(const std::string& path)
160 { 182 {
161 basePath = path; 183 basePath = path;
162 184
163 if ((*basePath.rbegin() == PATH_SEPARATOR)) 185 if (*basePath.rbegin() == PATH_SEPARATOR)
164 { 186 {
165 basePath.resize(basePath.size() - 1); 187 basePath.resize(basePath.size() - 1);
166 } 188 }
167 } 189 }
168 190
LEFTRIGHT

Powered by Google App Engine
This is Rietveld