MCPcopy Create free account
hub / github.com/DeusData/codebase-memory-mcp / cbm_canonical_path

Function cbm_canonical_path

src/foundation/compat_fs.c:964–1030  ·  view source on GitHub ↗

Canonicalize an EXISTING path (collapse `..`, resolve links/junctions): * realpath on POSIX; a final path queried from an opened handle on Windows. * The previous Windows callers used the ANSI CRT (_access/_fullpath) on UTF-8 * input — locale-dependent by construction: on a CJK system codepage (e.g. * Big5) the UTF-8 bytes of a CJK path re-decode into different characters and * canonicalizati

Source from the content-addressed store, hash-verified

962 * only lexical and would let an allowed-root check follow a junction outside
963 * the root. Returns 0 when the path does not exist or cannot be resolved. */
964int cbm_canonical_path(const char *path, char *out, size_t out_sz) {
965 if (!path || !out || out_sz == 0) {
966 return 0;
967 }
968#ifdef _WIN32
969 wchar_t *wpath = cbm_path_to_wide(path);
970 if (!wpath) {
971 return 0;
972 }
973 HANDLE handle = CreateFileW(wpath, FILE_READ_ATTRIBUTES,
974 FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, NULL,
975 OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, NULL);
976 free(wpath);
977 if (handle == INVALID_HANDLE_VALUE) {
978 return 0;
979 }
980 DWORD needed =
981 GetFinalPathNameByHandleW(handle, NULL, 0, FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
982 /* MAXDWORD keeps the +1 below safe; calloc rejects an unrepresentable
983 * capacity * sizeof(wchar_t) allocation on narrower size_t targets. */
984 if (needed == 0 || needed == MAXDWORD) {
985 (void)CloseHandle(handle);
986 return 0;
987 }
988 size_t capacity = (size_t)needed + 1;
989 wchar_t *wfull = calloc(capacity, sizeof(*wfull));
990 if (!wfull) {
991 (void)CloseHandle(handle);
992 return 0;
993 }
994 DWORD n = GetFinalPathNameByHandleW(handle, wfull, (DWORD)capacity,
995 FILE_NAME_NORMALIZED | VOLUME_NAME_DOS);
996 (void)CloseHandle(handle);
997 if (n == 0 || (size_t)n >= capacity) {
998 free(wfull);
999 return 0;
1000 }
1001
1002 /* Preserve the conventional DOS/UNC form returned by the old API while
1003 * retaining the handle-based resolution. */
1004 if (wcsncmp(wfull, L"\\\\?\\UNC\\", 8) == 0) {
1005 size_t tail_length = wcslen(wfull + 8);
1006 wmemmove(wfull + 2, wfull + 8, tail_length + 1);
1007 wfull[0] = L'\\';
1008 wfull[1] = L'\\';
1009 } else if (wcsncmp(wfull, L"\\\\?\\", 4) == 0) {
1010 size_t tail_length = wcslen(wfull + 4);
1011 wmemmove(wfull, wfull + 4, tail_length + 1);
1012 }
1013 char *utf8 = cbm_wide_to_utf8(wfull);
1014 free(wfull);
1015 if (!utf8) {
1016 return 0;
1017 }
1018 size_t len = strlen(utf8);
1019 if (len >= out_sz) {
1020 free(utf8);
1021 return 0;

Callers 15

main_run_allow_rootFunction · 0.85
main_resolve_executableFunction · 0.85
main_build_identityFunction · 0.85
main_session_contextFunction · 0.85
resolve_canonical_pathFunction · 0.85
mcp_resolve_windows_cmdFunction · 0.85
handle_index_startFunction · 0.85
application_set_contextFunction · 0.85

Calls 2

cbm_path_to_wideFunction · 0.85
cbm_wide_to_utf8Function · 0.85