mirror of
				https://github.com/jart/cosmopolitan.git
				synced 2025-10-26 11:10:58 +00:00 
			
		
		
		
	Fix bug with realpath() on Windows
This commit is contained in:
		
							parent
							
								
									2816df59b2
								
							
						
					
					
						commit
						f31a98d50a
					
				
					 4 changed files with 57 additions and 3 deletions
				
			
		|  | @ -27,6 +27,7 @@ | |||
| ╚─────────────────────────────────────────────────────────────────────────────*/ | ||||
| #include "libc/assert.h" | ||||
| #include "libc/calls/calls.h" | ||||
| #include "libc/dce.h" | ||||
| #include "libc/errno.h" | ||||
| #include "libc/intrin/safemacros.internal.h" | ||||
| #include "libc/limits.h" | ||||
|  | @ -41,6 +42,11 @@ __static_yoink("musl_libc_notice"); | |||
| 
 | ||||
| // clang-format off
 | ||||
| 
 | ||||
| static inline int IsAlpha(int c) | ||||
| { | ||||
| 	return ('A' <= c && c <= 'Z') || ('a' <= c && c <= 'z'); | ||||
| } | ||||
| 
 | ||||
| static size_t GetSlashLen(const char *s) | ||||
| { | ||||
| 	const char *s0 = s; | ||||
|  | @ -93,6 +99,33 @@ char *realpath(const char *filename, char *resolved) | |||
| 		einval(); | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Normalize windows paths before proceeding. */ | ||||
| 	if (IsWindows()) { | ||||
| 		int c, i = 0; | ||||
| 
 | ||||
| 		/* Turn backslash into slash. */ | ||||
| 		while ((c = *filename++)) { | ||||
| 			if (i == PATH_MAX - 1) | ||||
| 				goto toolong; | ||||
| 			if (c == '\\') | ||||
| 				c = '/'; | ||||
| 			output[i++] = c; | ||||
| 		} | ||||
| 		output[i] = 0; | ||||
| 
 | ||||
| 		/* Turn paths like "C:" into "/C"
 | ||||
| 		 * Turn paths like "C:/..." into "/C/..." */ | ||||
| 		if (IsAlpha(output[0]) && output[1] == ':' && | ||||
| 		    (!output[2] || output[2] == '/')) { | ||||
| 			output[1] = output[0]; | ||||
| 			output[0] = '/'; | ||||
| 		} | ||||
| 
 | ||||
| 		filename = output; | ||||
| 	} | ||||
| 
 | ||||
| 	/* Copy the path and handle ZipOS. */ | ||||
| 	l = strnlen(filename, sizeof stack); | ||||
| 	if (!l) { | ||||
| 		enoent(); | ||||
|  | @ -124,8 +157,7 @@ restart: | |||
| 			continue; | ||||
| 		} | ||||
| 
 | ||||
| 		z = (char *)min((intptr_t)strchrnul(stack+p, '/'), | ||||
| 				(intptr_t)strchrnul(stack+p, '\\')); | ||||
| 		z = strchrnul(stack+p, '/'); | ||||
| 		l0 = l = z-(stack+p); | ||||
| 
 | ||||
| 		if (!l && !check_dir) break; | ||||
|  |  | |||
|  | @ -112,3 +112,15 @@ TEST(readlinkat, realpathReturnsLongPath) { | |||
|   ASSERT_SYS(0, 0, touch("froot", 0644)); | ||||
|   ASSERT_STARTSWITH("/c/", realpath("froot", buf)); | ||||
| } | ||||
| 
 | ||||
| TEST(readlinkat, c_drive) { | ||||
|   char buf[PATH_MAX]; | ||||
|   ASSERT_SYS(EINVAL, -1, readlinkat(AT_FDCWD, "/", buf, PATH_MAX)); | ||||
|   if (!IsWindows()) | ||||
|     return; | ||||
|   ASSERT_SYS(EINVAL, -1, readlinkat(AT_FDCWD, "/c/", buf, PATH_MAX)); | ||||
|   ASSERT_SYS(EINVAL, -1, readlinkat(AT_FDCWD, "/c", buf, PATH_MAX)); | ||||
|   ASSERT_SYS(EINVAL, -1, readlinkat(AT_FDCWD, "c:", buf, PATH_MAX)); | ||||
|   ASSERT_SYS(EINVAL, -1, readlinkat(AT_FDCWD, "c:/", buf, PATH_MAX)); | ||||
|   ASSERT_SYS(EINVAL, -1, readlinkat(AT_FDCWD, "c:\\", buf, PATH_MAX)); | ||||
| } | ||||
|  |  | |||
|  | @ -20,6 +20,7 @@ | |||
| #include "libc/dce.h" | ||||
| #include "libc/errno.h" | ||||
| #include "libc/intrin/strace.internal.h" | ||||
| #include "libc/limits.h" | ||||
| #include "libc/mem/gc.h" | ||||
| #include "libc/mem/mem.h" | ||||
| #include "libc/runtime/runtime.h" | ||||
|  | @ -79,3 +80,12 @@ TEST(realpath, test6) { | |||
|   ASSERT_NE(NULL, name); | ||||
|   EXPECT_STREQ("/", name); | ||||
| } | ||||
| 
 | ||||
| TEST(realpath, c_drive) { | ||||
|   if (!IsWindows()) | ||||
|     return; | ||||
|   char buf[PATH_MAX]; | ||||
|   ASSERT_STREQ("/c", realpath("c:", buf)); | ||||
|   ASSERT_STREQ("/c", realpath("c:", buf)); | ||||
|   ASSERT_STREQ("/c/Windows", realpath("c:\\Windows", buf)); | ||||
| } | ||||
|  |  | |||
|  | @ -15,7 +15,7 @@ | |||
| #define _LIBCPP_SRC_INCLUDE_TO_CHARS_FLOATING_POINT_H | ||||
| 
 | ||||
| #pragma GCC diagnostic push | ||||
| #pragma GCC diagnostic warning "-Wattributes" | ||||
| #pragma GCC diagnostic ignored "-Wattributes" | ||||
| 
 | ||||
| // Avoid formatting to keep the changes with the original code minimal.
 | ||||
| // clang-format off
 | ||||
|  |  | |||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue