-
Notifications
You must be signed in to change notification settings - Fork 1.6k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
File APIs inconsistently handle paths ending in .
on windows in 3.4.3
#55972
Comments
Discovered when investigating dart-lang/test#2243. |
Fixes #2243 by not creating files that end in a `.`. https://gist.github.com/jakemac53/845b60847dbda53f93aeed8056d5fbd2 illustrates what I think is the core of the issue. I would expect this to print false and also hit the catch block for every case. However, on 3.4.0, in the very first case the copy actually succeeds even though it claims the file doesn't exist. I filed dart-lang/sdk#55972 about this.
Seems to be the absolute path which breaks import "dart:io";
void main() {
var test = File(r'test.');
try {
test.copySync(r'copyTest.txt');
print("Success");
} catch (e) {
print("$e");
}
test = test.absolute;
try {
test.copySync(r'copyTest.txt'); // Fails.
print("Success");
} catch (e) {
print("$e");
}
} Also works with |
https://dart-review.googlesource.com/c/sdk/+/356680 is the culprit |
Per https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file?redirectedfrom=MSDN#win32-file-namespaces on Windows you can't have (trailing) periods in filenames unless you prefix the filename with '\\?\'. Line 816 in ca3e67a
We could strip trailing periods before adding a prefix diff --git a/runtime/bin/file_win.cc b/runtime/bin/file_win.cc
index 66cadbedf1b..bf2c0c058e1 100644
--- a/runtime/bin/file_win.cc
+++ b/runtime/bin/file_win.cc
@@ -408,10 +408,14 @@ static std::unique_ptr<wchar_t[]> ToWinAPIPath(const char* utf8_path,
return absolute_path;
}
- // Add prefix and replace forward slashes with backward slashes.
+ // Add prefix, remove trailing periods, replace forward slashes with
+ // backward slashes.
auto result =
std::make_unique<wchar_t[]>(kLongPathPrefixLength + path_length + 1);
wcsncpy(result.get(), kLongPathPrefix, kLongPathPrefixLength);
+ if (is_file) {
+ while (path_length > 0 && absolute_path[path_length - 1] == '.') {
+ --path_length;
+ }
+ }
for (int i = 0; i < path_length; i++) {
result.get()[kLongPathPrefixLength + i] =
absolute_path[i] == L'/' ? L'\\' : absolute_path[i]; cc @mraleph |
@aam I don't think the proposed change is enough. Rules around trailing dots apply to all path components, not just the trailing one. Consider path I think we have a choice to make:
I am in doubt that we actually want option 2 - because it silently leads to a very surprising behavior, especially when people are trying to write portable code. I think we should go for either 1 or 3. I am leaning towards 1. Any opinions? |
I would be fine with either option 1 or 3, I would not be a fan of option 2, that seems very surprising. |
"Do not end a file or directory name with a space or a period. Although the underlying file system may support such names, the Windows shell and user interface does not." (https://learn.microsoft.com/en-us/windows/win32/fileio/naming-a-file) Also at present, if user wants to they can explicitly add '\?' prefix to a path/filename with trailing periods and file operations will work. import "dart:io";
void main() {
var test = File(r'\\?\c:\src\d2\sdk\test.');
test.writeAsStringSync('kuka');
try {
test.copySync(r'copyTest.txt');
print("Success");
} catch (e) {
print("$e");
}
test = test.absolute;
print(test.path);
try {
test.copySync(r'copyTest.txt'); // Fails.
print("Success");
} catch (e) {
print("$e");
}
} PS C:\src\d2\sdk> out\ReleaseX64\dart d1.dart
Success
\\?\c:\src\d2\sdk\test.
Success
PS C:\src\d2\sdk> |
Also note that Windows CLI shell as well as Windows Explorer does strip trailing periods from filenames automatically:
|
While stripping dots would be more "Windows-native", I think we should opt for supporting dots in filepaths instead - because we are multiplatform language. We already hide some of the WinAPI complexity away from users (e.g. we don't require them to know about We might want to add some warnings in |
https://dart-review.googlesource.com/c/sdk/+/375421 with the fix |
This ensures that on Windows we take advantage of 32k-character file name limit consistently for all files and directories operations. TEST=ci BUG=#56125 BUG=#55972 CoreLibraryReviewExempt: adds windows-specific error code for invalid file name Change-Id: I83bd3ceac579e589469e47b2cf5216db457cae8b Reviewed-on: https://dart-review.googlesource.com/c/sdk/+/375421 Reviewed-by: Slava Egorov <[email protected]> Commit-Queue: Alexander Aprelev <[email protected]>
See this gist https://gist.github.com/jakemac53/845b60847dbda53f93aeed8056d5fbd2.
Assuming the file does exist with that name (I think it is invalid, but it is possible to create at least on the command line), on 3.2.0 and 3.4.0 and greater we do consistently always claim the file does not exist. I am not sure if this in intended behavior or not, but at least it is consistent.
However, starting with at least 3.4.0, the first file copy (using the absolute file URI) succeeds, even though
exists()
returned false.I can't easily test this beyond 3.4.3 on my windows box, as I am not set up to do custom builds.
The text was updated successfully, but these errors were encountered: