In this code, when user inputs c:\\temp
, getcwd()
returns "c:\temp"
.
Actual path is C:\Temp
.
if(chdir(fullpath))
{
perror("cd");
return 1;
}
if(!getcwd(path, sizeof(path))
{
perror("getcwd error");
getchar();
exit(1);
}
I expected it to return "C:\\Temp"
. Is there any way to get case-sensitive current working directory in C? Wherever I searched, there was only getcwd()
.
Edit: Also, if user inputs c:\tEMp
, it returns the same. How can I prevent this?
In the comments, you said you wanted cross platform portability, but that's nearly impossible:
getcwd
is a Posix function, not part of the standard C run-time library.
On Posix systems, the distinction between the C run-time and the system libraries is usually fuzzy. Microsoft tries not to blur the line, but they did in the past, and so there remain some Posix-like definitions in the C run-time. On Windows, with the libraries provided with MSVC, getcwd
is actually a macro or wrapper that delegates to _getcwd
. It seems unlikely Microsoft would ever remove it, but they have deprecated getcwd
.
Even if you were willing to compromise on cross-platform portability by calling _getcwd
or even GetCurrentDirectoryA
, it's likely you'd eventually get tripped up by a path name that's not representable in whichever code page is in force. So you probably should be calling the Unicode-enabled "wide" versions of those APIs, but now your wannabe cross-platform code uses char
strings on some platforms and WCHAR
strings on another (and/or does extra work on Windows to convert to UTF-8 and to force the code page to CP_UTF8
in all the right places).
On Posix there is a single working directory for the process. On Windows, a process can have one working directory per drive letter. On Windows, functions like _getcwd
return the current current working directory.
Some will argue that working-directory-per-drive-letter is a shell or CMD convention and therefore not relevant. My point is that you cannot predict how an OS call like CreateFileW
will resolve a non-absolute path like D:foo.txt
unless you know the process's current working directory for the D:
drive, which requires non-portable platform specific code.
Windows Explorer uses WinAPI and its own rules for processing and presenting file system paths. A simple example is that, depending on the user's settings, Explorer might hide extensions for some files. Matching that behaviors requires platform-specific code.
Drive letters on Windows are an OS convention (inherited from CP/M through DOS), and not part of the underlying file system. So even if you switched your file system (all or part) to be case-sensitive, this would have no impact on the case sensitivity of the drive letters. (The OS convention is "don't care" though a lot of software conventionally presents them as capital letters.)
So what can you do?
Live with it as is.
Write code that recognizes a lowercase drive letter in a path and changes it to uppercase.
Use platform specific calls to get the OS to give the canonical name for that path.
This is difficult. For a file, you could open the file, and then use GetFinalPathNameByHandle
. You cannot open a directory as a file.
Neither GetFullPathName
nor GetLongFileName
do what you need either.
I think you'd have to use FindFirstFile
to get the official name of the last segment of the path. Then chop off that segment and "search" again to get the official name of its parent. Repeat until you reach the root.