LEFT | RIGHT |
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 Loading... |
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 || |
| 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 |
LEFT | RIGHT |