]> git.proxmox.com Git - cargo.git/commitdiff
Use GetFullPathNameW to test restricted names
authorEric Holk <ericholk@microsoft.com>
Mon, 24 Jan 2022 19:09:07 +0000 (11:09 -0800)
committerEric Holk <ericholk@microsoft.com>
Wed, 3 Aug 2022 22:59:58 +0000 (15:59 -0700)
The previous commit tests whether the current machine supports Windows
restricted names by creating a file and checking whether that succeeds.
This commit reworks this testto use GetFullPathNameW, which can be done
without having to create and remove new files.

src/cargo/util/restricted_names.rs
tests/testsuite/package.rs

index 650ae233059cbd23b88380d8a06019fdd54b9162..5dca878f5d2b8af9013fe967273c96edbf450bcc 100644 (file)
@@ -97,3 +97,59 @@ pub fn is_windows_reserved_path(path: &Path) -> bool {
 pub fn is_glob_pattern<T: AsRef<str>>(name: T) -> bool {
     name.as_ref().contains(&['*', '?', '[', ']'][..])
 }
+
+/// Returns true if names such as aux.* are allowed.
+///
+/// Traditionally, Windows did not allow a set of file names (see `is_windows_reserved_name`
+/// for a list). More recent versions of Windows have relaxed this restriction. This test
+/// determines whether we are running in a mode that allows Windows reserved names.
+pub fn windows_reserved_names_are_allowed() -> bool {
+    #[cfg(windows)]
+    {
+        use std::ffi::OsStr;
+        use std::os::windows::ffi::OsStrExt;
+        use std::ptr;
+        use winapi::um::fileapi::GetFullPathNameW;
+
+        let test_file_name: Vec<_> = OsStr::new("aux.rs").encode_wide().collect();
+
+        let buffer_length = unsafe {
+            GetFullPathNameW(test_file_name.as_ptr(), 0, ptr::null_mut(), ptr::null_mut())
+        };
+
+        if buffer_length == 0 {
+            // This means the call failed, so we'll conservatively assume reserved names are not allowed.
+            return false;
+        }
+
+        let mut buffer = vec![0u16; buffer_length as usize];
+
+        let result = unsafe {
+            GetFullPathNameW(
+                test_file_name.as_ptr(),
+                buffer_length,
+                buffer.as_mut_ptr(),
+                ptr::null_mut(),
+            )
+        };
+
+        if result == 0 {
+            // Once again, conservatively assume reserved names are not allowed if the
+            // GetFullPathNameW call failed.
+            return false;
+        }
+
+        // Under the old rules, a file name like aux.rs would get converted into \\.\aux, so
+        // we detect this case by checking if the string starts with \\.\
+        //
+        // Otherwise, the filename will be something like C:\Users\Foo\Documents\aux.rs
+        let prefix: Vec<_> = OsStr::new("\\\\.\\").encode_wide().collect();
+        if buffer.starts_with(&prefix) {
+            false
+        } else {
+            true
+        }
+    }
+    #[cfg(not(windows))]
+    true
+}
index 1d4cc423929002cfe1b0843ebb877ba726bf79a4..19ae6c639c73ae5a9e2034aa4a0502d451e26723 100644 (file)
@@ -2006,24 +2006,12 @@ src/lib.rs
         .run();
 }
 
-/// Certain versions of Windows 11 have removed the restriction on filenames. To detect whether
-/// this is the case, we try to create a file with a reserved name.
-#[cfg(windows)]
-fn windows_reserved_names_are_allowed() -> bool {
-    let test_file = paths::home().join("aux.rs");
-    if File::create(&test_file).is_err() {
-        return false;
-    }
-    let _ = fs::remove_file(test_file);
-    true
-}
-
 #[cargo_test]
 #[cfg(windows)]
 fn reserved_windows_name() {
     // If we are running on a version of Windows that allows these reserved filenames,
     // skip this test.
-    if windows_reserved_names_are_allowed() {
+    if cargo::util::restricted_names::windows_reserved_names_are_allowed() {
         return;
     }