Bug 1883861 - Part 1: Move visitMemoryBarrier into the common CodeGenerator file...
[gecko.git] / xpcom / tests / gtest / TestFileNTFSSpecialPaths.cpp
blob39b73a71480b6fe601e15a5fc74363c55c65b052
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this
4 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "prio.h"
7 #include "prsystem.h"
9 #include "mozilla/gtest/MozAssertions.h"
10 #include "nsComponentManagerUtils.h"
11 #include "nsIFile.h"
12 #include "nsILocalFileWin.h"
13 #include "nsString.h"
15 #define MAX_PATH 260
17 #include "gtest/gtest.h"
19 static void CanInitWith(const char* aPath, bool aShouldWork) {
20 nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
21 nsresult rv = file->InitWithNativePath(nsDependentCString(aPath));
22 bool success = aShouldWork ? NS_SUCCEEDED(rv) : NS_FAILED(rv);
23 EXPECT_TRUE(success) << "'" << aPath << "' rv=" << std::hex
24 << (unsigned int)rv;
27 static void CanAppend(const char* aRoot, const char* aPath, bool aShouldWork) {
28 nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
29 file->InitWithNativePath(nsDependentCString(aRoot));
30 nsAutoCString basePath;
31 file->GetNativeTarget(basePath);
33 nsresult rv = file->AppendNative(nsDependentCString(aPath));
34 bool success = aShouldWork ? NS_SUCCEEDED(rv) : NS_FAILED(rv);
35 EXPECT_TRUE(success) << "'" << basePath.get() << "' + '" << aPath
36 << "' rv=" << std::hex << (unsigned int)rv;
39 static void CanSetLeafName(const char* aRoot, const char* aPath,
40 bool aShouldWork) {
41 nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
42 file->InitWithNativePath(nsDependentCString(aRoot));
43 nsAutoCString basePath;
44 file->GetNativeTarget(basePath);
46 nsresult rv =
47 file->SetLeafName(NS_ConvertUTF8toUTF16(nsDependentCString(aPath)));
48 bool success = aShouldWork ? NS_SUCCEEDED(rv) : NS_FAILED(rv);
49 EXPECT_TRUE(success) << "'" << basePath.get() << "' set leaf to '" << aPath
50 << "' rv=" << std::hex << (unsigned int)rv;
53 TEST(TestFileNTFSSpecialPaths, PlainPaths)
55 CanInitWith("C:\\", true);
56 CanInitWith("C:\\foo", true);
57 CanInitWith("C:\\bar\\foo", true);
58 CanInitWith("C:\\bar\\foo\\", true);
60 CanAppend("C:\\", "foo", true);
61 CanAppend("C:\\", "bar", true);
62 CanAppend("C:\\bar", "foo", true);
64 CanSetLeafName("C:\\a", "foo", true);
65 CanSetLeafName("C:\\a", "bar", true);
68 TEST(TestFileNTFSSpecialPaths, AllowedSpecialChars)
70 CanInitWith("C:\\$foo", true);
71 CanInitWith("C:\\bar\\$foo", true);
72 CanInitWith("C:\\foo:Zone.Identifier", true);
73 CanInitWith("C:\\$foo:Zone.Identifier", true);
74 CanInitWith("C:\\bar\\$foo:Zone.Identifier", true);
76 CanAppend("C:\\", "$foo", true);
77 CanAppend("C:\\bar\\", "$foo", true);
78 CanAppend("C:\\", "foo:Zone.Identifier", true);
79 CanAppend("C:\\", "$foo:Zone.Identifier", true);
80 CanAppend("C:\\bar\\", "$foo:Zone.Identifier", true);
82 CanSetLeafName("C:\\a", "$foo", true);
83 CanSetLeafName("C:\\a", "foo:Zone.Identifier", true);
84 CanSetLeafName("C:\\a", "$foo:Zone.Identifier", true);
87 TEST(TestFileNTFSSpecialPaths, ForbiddenAttributes)
89 CanInitWith("C:\\:$MFT", false);
90 CanInitWith("C:\\:$mft", false);
91 CanInitWith("C:\\:$foo", false);
92 // nsLocalFileWin strips the trailing slash so this should also fail:
93 CanInitWith("C:\\:$MFT\\", false);
94 CanInitWith("C:\\:$mft\\", false);
95 CanInitWith("C:\\:$foo\\", false);
97 // We just block these everywhere, not just at the root:
98 CanInitWith("C:\\bar\\:$mft", false);
99 CanInitWith("C:\\bar\\:$mft\\", false);
100 CanInitWith("C:\\bar\\:$foo", false);
101 CanInitWith("C:\\bar\\:$foo\\", false);
103 // Now do the same for appending.
104 CanAppend("C:\\", ":$MFT", false);
105 CanAppend("C:\\", ":$mft", false);
106 CanAppend("C:\\", ":$foo", false);
107 // nsLocalFileWin strips the trailing slash so this should also fail:
108 CanAppend("C:\\", ":$MFT\\", false);
109 CanAppend("C:\\", ":$mft\\", false);
110 CanAppend("C:\\", ":$foo\\", false);
112 // We just block these everywhere, not just at the root:
113 CanAppend("C:\\bar\\", ":$mft", false);
114 CanAppend("C:\\bar\\", ":$mft\\", false);
115 CanAppend("C:\\bar\\", ":$foo", false);
116 CanAppend("C:\\bar\\", ":$foo\\", false);
118 // And the same thing for leaf names:
119 CanSetLeafName("C:\\a", ":$MFT", false);
120 CanSetLeafName("C:\\a", ":$mft", false);
121 CanSetLeafName("C:\\a", ":$foo", false);
123 CanSetLeafName("C:\\a", ":$MFT\\", false);
124 CanSetLeafName("C:\\a", ":$mft\\", false);
125 CanSetLeafName("C:\\a", ":$foo\\", false);
127 CanSetLeafName("C:\\bar\\foo", ":$mft", false);
128 CanSetLeafName("C:\\bar\\foo", ":$mft\\", false);
129 CanSetLeafName("C:\\bar\\foo", ":$foo", false);
130 CanSetLeafName("C:\\bar\\foo", ":$foo\\", false);
133 TEST(TestFileNTFSSpecialPaths, ForbiddenMetaFiles)
135 CanInitWith("C:\\$MFT", false);
136 CanInitWith("C:\\$mft", false);
137 CanInitWith("C:\\$bitmap", false);
139 CanAppend("C:\\", "$MFT", false);
140 CanAppend("C:\\", "$mft", false);
141 CanAppend("C:\\", "$bitmap", false);
143 CanSetLeafName("C:\\a", "$MFT", false);
144 CanSetLeafName("C:\\a", "$mft", false);
145 CanSetLeafName("C:\\a", "$bitmap", false);
147 // nsLocalFileWin strips the trailing slash so this should also fail:
148 CanInitWith("C:\\$MFT\\", false);
149 CanInitWith("C:\\$mft\\", false);
150 CanInitWith("C:\\$bitmap\\", false);
152 CanAppend("C:\\", "$MFT\\", false);
153 CanAppend("C:\\", "$mft\\", false);
154 CanAppend("C:\\", "$bitmap\\", false);
156 CanSetLeafName("C:\\a", "$MFT\\", false);
157 CanSetLeafName("C:\\a", "$mft\\", false);
158 CanSetLeafName("C:\\a", "$bitmap\\", false);
160 // Shouldn't be able to bypass this by asking for ADS stuff:
161 CanInitWith("C:\\$MFT:Zone.Identifier", false);
162 CanInitWith("C:\\$mft:Zone.Identifier", false);
163 CanInitWith("C:\\$bitmap:Zone.Identifier", false);
165 CanAppend("C:\\", "$MFT:Zone.Identifier", false);
166 CanAppend("C:\\", "$mft:Zone.Identifier", false);
167 CanAppend("C:\\", "$bitmap:Zone.Identifier", false);
169 CanSetLeafName("C:\\a", "$MFT:Zone.Identifier", false);
170 CanSetLeafName("C:\\a", "$mft:Zone.Identifier", false);
171 CanSetLeafName("C:\\a", "$bitmap:Zone.Identifier", false);
174 TEST(TestFileNTFSSpecialPaths, ForbiddenMetaFilesOtherRoots)
176 // Should still block them for UNC and volume roots
177 CanInitWith("\\\\LOCALHOST\\C$\\$MFT", false);
178 CanInitWith("\\\\?\\Volume{1234567}\\$MFT", false);
180 CanAppend("\\\\LOCALHOST\\", "C$\\$MFT", false);
181 CanAppend("\\\\LOCALHOST\\C$\\", "$MFT", false);
182 CanAppend("\\\\?\\Volume{1234567}\\", "$MFT", false);
183 CanAppend("\\\\Blah\\", "Volume{1234567}\\$MFT", false);
185 CanSetLeafName("\\\\LOCALHOST\\C$", "C$\\$MFT", false);
186 CanSetLeafName("\\\\LOCALHOST\\C$\\foo", "$MFT", false);
187 CanSetLeafName("\\\\?\\Volume{1234567}\\foo", "$MFT", false);
188 CanSetLeafName("\\\\Blah\\foo", "Volume{1234567}\\$MFT", false);
190 // Root detection should cope with un-normalized paths:
191 CanInitWith("C:\\foo\\..\\$MFT", false);
192 CanInitWith("C:\\foo\\..\\$mft\\", false);
193 CanInitWith("\\\\LOCALHOST\\C$\\blah\\..\\$MFT", false);
194 CanInitWith("\\\\?\\Volume{13455635}\\blah\\..\\$MFT", false);
195 // As well as different or duplicated separators:
196 CanInitWith("C:\\foo\\..\\\\$MFT\\", false);
197 CanInitWith("\\\\?\\Volume{1234567}/$MFT", false);
198 CanInitWith("\\\\LOCALHOST\\C$/blah//../$MFT", false);
200 // There are no "append" equivalents for the preceding set of tests,
201 // because append does not allow '..' to be used as a relative path
202 // component, nor does it allow forward slashes:
203 CanAppend("C:\\foo", "..\\", false);
204 CanAppend("C:\\foo", "bar/baz", false);
206 // But this is (strangely) allowed for SetLeafName. Yes, really.
207 CanSetLeafName("C:\\foo\\bar", "..\\$MFT", false);
208 CanSetLeafName("C:\\foo\\bar", "..\\$mft\\", false);
209 CanSetLeafName("\\\\LOCALHOST\\C$\\bl", "ah\\..\\$MFT", false);
210 CanSetLeafName("\\\\?\\Volume{13455635}\\bla", "ah\\..\\$MFT", false);
212 CanSetLeafName("C:\\foo\\bar", "..\\\\$MFT\\", false);
213 CanSetLeafName("\\\\?\\Volume{1234567}\\bar", "/$MFT", false);
214 CanSetLeafName("\\\\LOCALHOST\\C$/blah/", "\\../$MFT", false);
217 TEST(TestFileNTFSSpecialPaths, NotQuiteMetaFiles)
219 // These files should not be blocked away from the root:
220 CanInitWith("C:\\bar\\$bitmap", true);
221 CanInitWith("C:\\bar\\$mft", true);
223 // Same for append:
224 CanAppend("C:\\bar\\", "$bitmap", true);
225 CanAppend("C:\\bar\\", "$mft", true);
227 // And SetLeafName:
228 CanSetLeafName("C:\\bar\\foo", "$bitmap", true);
229 CanSetLeafName("C:\\bar\\foo", "$mft", true);
231 // And we shouldn't block on substring matches:
232 CanInitWith("C:\\$MFT stocks", true);
233 CanAppend("C:\\", "$MFT stocks", true);
234 CanSetLeafName("C:\\", "$MFT stocks", true);
237 TEST(TestFileNTFSSpecialPaths, Normalization)
239 // First determine the working directory:
240 wchar_t workingDir[MAX_PATH];
241 if (nullptr == _wgetcwd(workingDir, MAX_PATH - 1)) {
242 EXPECT_FALSE(true) << "Getting working directory failed.";
243 return;
246 nsString normalizedPath(workingDir);
247 // Need at least 3 chars for the root, at least 2 more to get another subdir
248 // in there. This test will fail if cwd is the root of a drive.
249 if (normalizedPath.Length() < 5 ||
250 !mozilla::IsAsciiAlpha(normalizedPath.First()) ||
251 normalizedPath.CharAt(1) != L':' || normalizedPath.CharAt(2) != L'\\') {
252 EXPECT_FALSE(true) << "Working directory not long enough?!";
253 return;
256 // Copy the drive and colon, but NOT the backslash.
257 nsAutoString startingFilePath(Substring(normalizedPath, 0, 2));
258 normalizedPath.Cut(0, 3);
260 // Then determine the number of path components in cwd:
261 nsAString::const_iterator begin, end;
262 normalizedPath.BeginReading(begin);
263 normalizedPath.EndReading(end);
264 if (!FindCharInReadable(L'\\', begin, end)) {
265 EXPECT_FALSE(true) << "Working directory was at a root";
266 return;
268 auto numberOfComponentsAboveRoot = 1;
269 while (FindCharInReadable(L'\\', begin, end)) {
270 begin++;
271 numberOfComponentsAboveRoot++;
274 // Then set up a file with that many `..\` components:
275 startingFilePath.SetCapacity(3 + numberOfComponentsAboveRoot * 3 + 9);
276 while (numberOfComponentsAboveRoot--) {
277 startingFilePath.AppendLiteral(u"..\\");
279 startingFilePath.AppendLiteral(u"$mft");
281 nsCOMPtr<nsIFile> file = do_CreateInstance(NS_LOCAL_FILE_CONTRACTID);
282 // This should fail immediately, rather than waiting for a call to
283 // nsIFile::Normalize, because normalization doesn't happen reliably,
284 // and where it does happen consumers often don't check for errors.
285 nsresult rv = file->InitWithPath(startingFilePath);
286 EXPECT_NS_FAILED(rv) << " from normalizing '"
287 << NS_ConvertUTF16toUTF8(startingFilePath).get()
288 << "' rv=" << std::hex << (unsigned int)rv;