Skip to content
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
26 changes: 22 additions & 4 deletions src/runtime/io.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -958,17 +958,35 @@ extern "C" LEAN_EXPORT obj_res lean_io_realpath(obj_arg fname, obj_arg) {
#if defined(LEAN_WINDOWS)
constexpr unsigned BufferSize = 8192;
char buffer[BufferSize];
DWORD retval = GetFullPathName(string_cstr(fname), BufferSize, buffer, nullptr);
HANDLE handle = CreateFile(string_cstr(fname), 0, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
if (handle == INVALID_HANDLE_VALUE) {
obj_res res = mk_file_not_found_error(fname);
dec_ref(fname);
return res;
}
DWORD retval = GetFinalPathNameByHandle(handle, buffer, BufferSize, 0);
CloseHandle(handle);
if (retval == 0 || retval > BufferSize) {
return io_result_mk_ok(fname);
} else {
dec_ref(fname);
char * res = buffer;
if (memcmp(res, "\\\\?\\", 4) == 0) {
if (memcmp(res + 4, "UNC\\", 4) == 0) {
// network path: convert "\\\\?\\UNC\\..." to "\\\\..."
res[6] = '\\';
res += 6;
} else {
// simple path: convert "\\\\?\\C:\\.." to "C:\\..."
res += 4;
}
}
Comment on lines +974 to +983
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is this adopted from anywhere else, any other reference?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Originally Cameron told me about this stackoverflow post. It also seems like some implementations have something similar, e.g. java's file code.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also, from the documentation here: https://learn.microsoft.com/en-us/windows/win32/fileio/maximum-file-path-limitation?tabs=registry

The "\\?\" prefix can also be used with paths constructed according to the universal naming convention (UNC). To specify such a path using UNC, use the "\\?\UNC\" prefix.

// Hack for making sure disk is lower case
// TODO(Leo): more robust solution
if (strlen(buffer) >= 2 && buffer[1] == ':') {
buffer[0] = tolower(buffer[0]);
if (strlen(res) >= 2 && res[1] == ':') {
res[0] = tolower(res[0]);
}
return io_result_mk_ok(mk_string(buffer));
return io_result_mk_ok(mk_string(res));
}
#else
char buffer[PATH_MAX];
Expand Down
25 changes: 0 additions & 25 deletions src/util/path.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -233,29 +233,4 @@ std::vector<std::string> read_dir(std::string const &dirname) {
#endif
return files;
}

std::string lrealpath(std::string const & fname) {
#if defined(LEAN_EMSCRIPTEN)
return fname;
#elif defined(LEAN_WINDOWS)
constexpr unsigned BufferSize = 8192;
char buffer[BufferSize];
DWORD retval = GetFullPathName(fname.c_str(), BufferSize, buffer, nullptr);
if (retval == 0 || retval > BufferSize) {
return fname;
} else {
return std::string(buffer);
}
#else
constexpr unsigned BufferSize = 8192;
char buffer[BufferSize];
char * tmp = realpath(fname.c_str(), buffer);
if (tmp) {
std::string r(tmp);
return r;
} else {
throw file_not_found_exception(fname);
}
#endif
}
}
2 changes: 0 additions & 2 deletions src/util/path.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,4 @@ optional<bool> is_dir(std::string const & fn);
std::vector<std::string> read_dir(std::string const & dirname);

time_t get_mtime(std::string const & fname);

LEAN_EXPORT std::string lrealpath(std::string const & fname);
}
5 changes: 1 addition & 4 deletions tests/lean/run/parsePrelude.lean
Original file line number Diff line number Diff line change
@@ -1,9 +1,6 @@
import Lean.Parser

def test : IO Unit :=
if System.Platform.isWindows then
pure () -- TODO investigate why the following doesn't work on Windows
else do
def test : IO Unit := do
let env ← Lean.mkEmptyEnvironment;
discard <| Lean.Parser.testParseFile env (System.mkFilePath ["..", "..", "..", "src", "Init", "Prelude.lean"]);
IO.println "done"
Expand Down
19 changes: 19 additions & 0 deletions tests/lean/run/realPath.lean
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
def realPathTest : IO Unit := do
unless System.Platform.isWindows do
return
let dir ← IO.currentDir
let tmpDir := dir / "tmp_realpath_test_dir"
let tmpJunct := dir / "tmp_realpath_test_junction"
IO.FS.createDir (dir / tmpDir)
let cmd := "cmd.exe\" /c mklink /j \"" ++ tmpJunct.toString ++ "\" \"" ++ tmpDir.toString
discard <| IO.Process.run { cmd }
let realPath1 ← IO.FS.realPath tmpDir
let realPath2 ← IO.FS.realPath tmpJunct
let cmd := "cmd.exe\" /c rmdir \"" ++ tmpJunct.toString
discard <| IO.Process.run { cmd }
let cmd := "cmd.exe\" /c rmdir \"" ++ tmpDir.toString
discard <| IO.Process.run { cmd }
if realPath1 != realPath2 then
throw (.userError ("mismatch " ++ realPath1.toString ++ " with " ++ realPath2.toString))

#eval realPathTest
Loading