luaur_cli_lib/functions/get_current_working_directory.rs
1pub fn get_current_working_directory() -> Option<alloc::string::String> {
2 const MAX_PATH_LENGTH: usize = 131072;
3 const INITIAL_PATH_LENGTH: usize = 260;
4
5 let mut buffer = alloc::vec![0u8; INITIAL_PATH_LENGTH];
6 let mut current_len = INITIAL_PATH_LENGTH;
7
8 loop {
9 let result = unsafe {
10 #[cfg(windows)]
11 {
12 use core::ffi::{c_char, c_int};
13 extern "C" {
14 fn _getcwd(buffer: *mut c_char, maxlen: c_int) -> *mut c_char;
15 }
16 _getcwd(buffer.as_mut_ptr() as *mut c_char, buffer.len() as c_int)
17 }
18 #[cfg(not(windows))]
19 {
20 use core::ffi::{c_char, c_ulong};
21 extern "C" {
22 fn getcwd(buffer: *mut c_char, size: usize) -> *mut c_char;
23 }
24 getcwd(buffer.as_mut_ptr() as *mut c_char, buffer.len())
25 }
26 };
27
28 if !result.is_null() {
29 let c_str = unsafe { core::ffi::CStr::from_ptr(result) };
30 // The require resolver / VfsNavigator work in a forward-slash virtual
31 // path space (they split and join on '/'). On Windows `_getcwd` returns
32 // backslashes and a drive letter (e.g. `D:\a\luaur`), which the resolver
33 // treated as one opaque component: the drive never componentized,
34 // `absolute_path_prefix` kept backslashes while `get_module_path` stripped
35 // the drive with forward slashes, and the two were concatenated into an
36 // inconsistent cache key. That broke require cycle detection on Windows
37 // (the same module got different keys), so a module that re-required
38 // itself recursed forever -> stack overflow (0xC0000409) across the
39 // require-by-string tests. Normalize to forward slashes here so Windows
40 // drive-letter cwds flow through the resolver exactly like POSIX paths.
41 // No-op on Unix (POSIX paths contain no backslashes).
42 return Some(c_str.to_string_lossy().replace('\\', "/"));
43 }
44
45 let err = std::io::Error::last_os_error();
46 if err.raw_os_error() != Some(34) || current_len * 2 > MAX_PATH_LENGTH {
47 return None;
48 }
49
50 current_len *= 2;
51 buffer.resize(current_len, 0);
52 }
53}