Skip to main content

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}