mirror of
https://github.com/jart/cosmopolitan.git
synced 2025-05-29 08:42:28 +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/assert.h"
|
||||||
#include "libc/calls/calls.h"
|
#include "libc/calls/calls.h"
|
||||||
|
#include "libc/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/safemacros.internal.h"
|
#include "libc/intrin/safemacros.internal.h"
|
||||||
#include "libc/limits.h"
|
#include "libc/limits.h"
|
||||||
|
@ -41,6 +42,11 @@ __static_yoink("musl_libc_notice");
|
||||||
|
|
||||||
// clang-format off
|
// 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)
|
static size_t GetSlashLen(const char *s)
|
||||||
{
|
{
|
||||||
const char *s0 = s;
|
const char *s0 = s;
|
||||||
|
@ -93,6 +99,33 @@ char *realpath(const char *filename, char *resolved)
|
||||||
einval();
|
einval();
|
||||||
return 0;
|
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);
|
l = strnlen(filename, sizeof stack);
|
||||||
if (!l) {
|
if (!l) {
|
||||||
enoent();
|
enoent();
|
||||||
|
@ -124,8 +157,7 @@ restart:
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
z = (char *)min((intptr_t)strchrnul(stack+p, '/'),
|
z = strchrnul(stack+p, '/');
|
||||||
(intptr_t)strchrnul(stack+p, '\\'));
|
|
||||||
l0 = l = z-(stack+p);
|
l0 = l = z-(stack+p);
|
||||||
|
|
||||||
if (!l && !check_dir) break;
|
if (!l && !check_dir) break;
|
||||||
|
|
|
@ -112,3 +112,15 @@ TEST(readlinkat, realpathReturnsLongPath) {
|
||||||
ASSERT_SYS(0, 0, touch("froot", 0644));
|
ASSERT_SYS(0, 0, touch("froot", 0644));
|
||||||
ASSERT_STARTSWITH("/c/", realpath("froot", buf));
|
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/dce.h"
|
||||||
#include "libc/errno.h"
|
#include "libc/errno.h"
|
||||||
#include "libc/intrin/strace.internal.h"
|
#include "libc/intrin/strace.internal.h"
|
||||||
|
#include "libc/limits.h"
|
||||||
#include "libc/mem/gc.h"
|
#include "libc/mem/gc.h"
|
||||||
#include "libc/mem/mem.h"
|
#include "libc/mem/mem.h"
|
||||||
#include "libc/runtime/runtime.h"
|
#include "libc/runtime/runtime.h"
|
||||||
|
@ -79,3 +80,12 @@ TEST(realpath, test6) {
|
||||||
ASSERT_NE(NULL, name);
|
ASSERT_NE(NULL, name);
|
||||||
EXPECT_STREQ("/", 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
|
#define _LIBCPP_SRC_INCLUDE_TO_CHARS_FLOATING_POINT_H
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#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.
|
// Avoid formatting to keep the changes with the original code minimal.
|
||||||
// clang-format off
|
// clang-format off
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue