Skip to content

Commit 2063c1e

Browse files
authored
Implement winapi.GetLongPathName (#6525)
1 parent bcdf37b commit 2063c1e

File tree

2 files changed

+48
-4
lines changed

2 files changed

+48
-4
lines changed

Lib/test/test_winapi.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,8 +110,6 @@ def test_max_events_waitany(self):
110110

111111

112112
class WinAPITests(unittest.TestCase):
113-
# TODO: RUSTPYTHON
114-
@unittest.expectedFailure
115113
def test_getlongpathname(self):
116114
testfn = pathlib.Path(os.getenv("ProgramFiles")).parents[-1] / "PROGRA~1"
117115
if not os.path.isdir(testfn):
@@ -128,8 +126,6 @@ def test_getlongpathname(self):
128126
candidates = set(testfn.parent.glob("Progra*"))
129127
self.assertIn(pathlib.Path(actual), candidates)
130128

131-
# TODO: RUSTPYTHON
132-
@unittest.expectedFailure
133129
def test_getshortpathname(self):
134130
testfn = pathlib.Path(os.getenv("ProgramFiles"))
135131
if not os.path.isdir(testfn):

crates/vm/src/stdlib/winapi.rs

Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -677,4 +677,52 @@ mod _winapi {
677677

678678
Ok(WinHandle(handle))
679679
}
680+
681+
/// Helper for GetShortPathName and GetLongPathName
682+
fn get_path_name_impl(
683+
path: &PyStrRef,
684+
api_fn: unsafe extern "system" fn(*const u16, *mut u16, u32) -> u32,
685+
vm: &VirtualMachine,
686+
) -> PyResult<PyStrRef> {
687+
use rustpython_common::wtf8::Wtf8Buf;
688+
689+
let path_wide = path.as_wtf8().to_wide_with_nul();
690+
691+
// First call to get required buffer size
692+
let size = unsafe { api_fn(path_wide.as_ptr(), null_mut(), 0) };
693+
694+
if size == 0 {
695+
return Err(vm.new_last_os_error());
696+
}
697+
698+
// Second call to get the actual path
699+
let mut buffer: Vec<u16> = vec![0; size as usize];
700+
let result =
701+
unsafe { api_fn(path_wide.as_ptr(), buffer.as_mut_ptr(), buffer.len() as u32) };
702+
703+
if result == 0 {
704+
return Err(vm.new_last_os_error());
705+
}
706+
707+
// Truncate to actual length (excluding null terminator)
708+
buffer.truncate(result as usize);
709+
710+
// Convert UTF-16 back to WTF-8 (handles surrogates properly)
711+
let result_str = Wtf8Buf::from_wide(&buffer);
712+
Ok(vm.ctx.new_str(result_str))
713+
}
714+
715+
/// GetShortPathName - Return the short version of the provided path.
716+
#[pyfunction]
717+
fn GetShortPathName(path: PyStrRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
718+
use windows_sys::Win32::Storage::FileSystem::GetShortPathNameW;
719+
get_path_name_impl(&path, GetShortPathNameW, vm)
720+
}
721+
722+
/// GetLongPathName - Return the long version of the provided path.
723+
#[pyfunction]
724+
fn GetLongPathName(path: PyStrRef, vm: &VirtualMachine) -> PyResult<PyStrRef> {
725+
use windows_sys::Win32::Storage::FileSystem::GetLongPathNameW;
726+
get_path_name_impl(&path, GetLongPathNameW, vm)
727+
}
680728
}

0 commit comments

Comments
 (0)