Created
October 7, 2009 15:08
-
-
Save nobu/204118 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Index: include/ruby/io.h | |
=================================================================== | |
--- include/ruby/io.h (revision 25257) | |
+++ include/ruby/io.h (working copy) | |
@@ -167,4 +167,9 @@ int rb_io_read_pending(rb_io_t*); | |
void rb_read_check(FILE*); | |
+char *rb_enc_path_next(const char *s, const char *e, rb_encoding *enc); | |
+char *rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc); | |
+char *rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc); | |
+char *rb_enc_path_end(const char *path, const char *end, rb_encoding *enc); | |
+ | |
#if defined(__cplusplus) | |
#if 0 | |
Index: file.c | |
=================================================================== | |
--- file.c (revision 25257) | |
+++ file.c (working copy) | |
@@ -2494,7 +2494,8 @@ rb_file_s_umask(int argc, VALUE *argv) | |
#endif | |
-#ifndef CharNext /* defined as CharNext[AW] on Windows. */ | |
-# define CharNext(p) ((p) + 1) | |
-#endif | |
+#define Next(p, e, enc) (p + rb_enc_mbclen(p, e, enc)) | |
+#define Inc(p, e, enc) ((p) = Next(p, e, enc)) | |
+ | |
+#define fs_encoding() rb_filesystem_encoding() | |
#ifdef DOSISH_DRIVE_LETTER | |
@@ -2510,9 +2511,29 @@ has_drive_letter(const char *buf) | |
} | |
-static char* | |
-getcwdofdrv(int drv) | |
+#define has_drive_letter2(buf, end) ((buf) + 2 <= (end) && has_drive_letter(buf)) | |
+ | |
+static VALUE | |
+w32_getcwd(VALUE result) | |
+{ | |
+ VALUE cwd, tmp; | |
+ DWORD len = GetCurrentDirectoryW(0, NULL); | |
+ rb_encoding *utf16_le = rb_enc_find("utf16-le"); | |
+ | |
+ cwd = rb_enc_str_new(0, sizeof(wchar_t) * len, utf16_le); | |
+ len = GetCurrentDirectoryW(len, (wchar_t *)RSTRING_PTR(cwd)); | |
+ rb_str_set_len(cwd, sizeof(wchar_t) * len); | |
+ tmp = cwd; | |
+ cwd = rb_str_encode(tmp, rb_enc_from_encoding(rb_enc_get(result)), 0, Qnil); | |
+ rb_str_resize(tmp, 0); | |
+ rb_str_shared_replace(result, cwd); | |
+ return result; | |
+} | |
+ | |
+static VALUE | |
+getcwdofdrv(int drv, VALUE result) | |
{ | |
char drive[4]; | |
- char *drvcwd, *oldcwd; | |
+ VALUE oldcwd; | |
+ DWORD len; | |
drive[0] = drv; | |
@@ -2524,23 +2545,26 @@ getcwdofdrv(int drv) | |
so save the old cwd before chdir() | |
*/ | |
- oldcwd = my_getcwd(); | |
+ len = GetCurrentDirectoryW(0, NULL); | |
+ oldcwd = rb_str_buf_new(sizeof(wchar_t) * len); | |
+ GetCurrentDirectoryW(len, (wchar_t *)RSTRING_PTR(oldcwd)); | |
if (chdir(drive) == 0) { | |
- drvcwd = my_getcwd(); | |
- chdir(oldcwd); | |
- xfree(oldcwd); | |
+ w32_getcwd(result); | |
+ SetCurrentDirectoryW((wchar_t *)RSTRING_PTR(oldcwd)); | |
} | |
else { | |
/* perhaps the drive is not exist. we return only drive letter */ | |
- drvcwd = strdup(drive); | |
+ rb_str_resize(result, 0); | |
+ rb_str_cat(result, drive, 2); | |
} | |
- return drvcwd; | |
+ rb_str_resize(oldcwd, 0); | |
+ return result; | |
} | |
#endif | |
static inline char * | |
-skiproot(const char *path) | |
+skiproot(const char *path, const char *end) | |
{ | |
#ifdef DOSISH_DRIVE_LETTER | |
- if (has_drive_letter(path)) path += 2; | |
+ if (has_drive_letter2(path, end)) path += 2; | |
#endif | |
while (isdirsep(*path)) path++; | |
@@ -2548,21 +2572,35 @@ skiproot(const char *path) | |
} | |
-#define nextdirsep rb_path_next | |
-char * | |
-rb_path_next(const char *s) | |
+static inline char * | |
+nextdirsep(const char *s) | |
{ | |
while (*s && !isdirsep(*s)) { | |
- s = CharNext(s); | |
+ s++; | |
} | |
return (char *)s; | |
} | |
-#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) | |
-#define skipprefix rb_path_skip_prefix | |
-#else | |
-#define skipprefix(path) (path) | |
-#endif | |
char * | |
-rb_path_skip_prefix(const char *path) | |
+rb_enc_path_next(const char *s, const char *e, rb_encoding *enc) | |
+{ | |
+ while (s < e && !isdirsep(*s)) { | |
+ Inc(s, e, enc); | |
+ } | |
+ return (char *)s; | |
+} | |
+ | |
+char * | |
+rb_path_next(const char *s) | |
+{ | |
+ rb_encoding *enc = fs_encoding(); | |
+ if (enc) { | |
+ return rb_enc_path_next(s, s + strlen(s), enc); | |
+ } | |
+ return nextdirsep(s); | |
+} | |
+ | |
+#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) | |
+static char * | |
+skipprefix(const char *path) | |
{ | |
#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) | |
@@ -2583,19 +2621,55 @@ rb_path_skip_prefix(const char *path) | |
return (char *)path; | |
} | |
+#else | |
+#define skipprefix(path) ((char *)(path)) | |
+#endif | |
+char * | |
+rb_enc_path_skip_prefix(const char *path, const char *end, rb_encoding *enc) | |
+{ | |
+#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) | |
+ if (path + 2 > end) return (char *)path; | |
+#ifdef DOSISH_UNC | |
+ if (isdirsep(path[0]) && isdirsep(path[1])) { | |
+ path += 2; | |
+ while (isdirsep(*path)) path++; | |
+ if ((path = rb_enc_path_next(path, end, enc)) < end && !isdirsep(path[1])) | |
+ path = rb_enc_path_next(path + 1, end, enc); | |
+ return (char *)path; | |
+ } | |
+#endif | |
+#ifdef DOSISH_DRIVE_LETTER | |
+ if (has_drive_letter2(path, end)) | |
+ return (char *)(path + 2); | |
+#endif | |
+#endif | |
+ return (char *)path; | |
+} | |
-#define strrdirsep rb_path_last_separator | |
char * | |
-rb_path_last_separator(const char *path) | |
+rb_path_skip_prefix(const char *path) | |
+{ | |
+#if defined(DOSISH_UNC) || defined(DOSISH_DRIVE_LETTER) | |
+ rb_encoding *enc = fs_encoding(); | |
+ if (enc) { | |
+ return rb_enc_path_skip_prefix(path, path + strlen(path), enc); | |
+ } | |
+#endif | |
+ return skipprefix(path); | |
+} | |
+ | |
+static char * | |
+strrdirsep(const char *path) | |
{ | |
char *last = NULL; | |
while (*path) { | |
if (isdirsep(*path)) { | |
- const char *tmp = path++; | |
- while (isdirsep(*path)) path++; | |
- if (!*path) break; | |
+ const char *tmp = path; | |
+ do { | |
+ if (!*++path) return last; | |
+ } while (isdirsep(*path)); | |
last = (char *)tmp; | |
} | |
else { | |
- path = CharNext(path); | |
+ path++; | |
} | |
} | |
@@ -2603,4 +2677,33 @@ rb_path_last_separator(const char *path) | |
} | |
+char * | |
+rb_enc_path_last_separator(const char *path, const char *end, rb_encoding *enc) | |
+{ | |
+ char *last = NULL; | |
+ while (path < end) { | |
+ if (isdirsep(*path)) { | |
+ const char *tmp = path; | |
+ do { | |
+ if (++path >= end) return last; | |
+ } while (isdirsep(*path)); | |
+ last = (char *)tmp; | |
+ } | |
+ else { | |
+ Inc(path, end, enc); | |
+ } | |
+ } | |
+ return last; | |
+} | |
+ | |
+char * | |
+rb_path_last_separator(const char *path) | |
+{ | |
+ rb_encoding *enc = fs_encoding(); | |
+ if (enc) { | |
+ return rb_enc_path_last_separator(path, path + strlen(path), enc); | |
+ } | |
+ return strrdirsep(path); | |
+} | |
+ | |
static char * | |
chompdirsep(const char *path) | |
@@ -2608,11 +2711,25 @@ chompdirsep(const char *path) | |
while (*path) { | |
if (isdirsep(*path)) { | |
- const char *last = path++; | |
- while (isdirsep(*path)) path++; | |
- if (!*path) return (char *)last; | |
+ const char *last = path; | |
+ do { | |
+ if (!*++path) return (char *)last; | |
+ } while (isdirsep(*path)); | |
} | |
- else { | |
- path = CharNext(path); | |
+ path++; | |
+ } | |
+ return (char *)path; | |
+} | |
+ | |
+static char * | |
+chompdirsep_enc(const char *path, const char *end, rb_encoding *enc) | |
+{ | |
+ while (path < end) { | |
+ if (isdirsep(*path)) { | |
+ const char *last = path; | |
+ do { | |
+ if (!*++path) return (char *)last; | |
+ } while (isdirsep(*path)); | |
} | |
+ Inc(path, end, enc); | |
} | |
return (char *)path; | |
@@ -2622,31 +2739,60 @@ char * | |
rb_path_end(const char *path) | |
{ | |
+ rb_encoding *enc = fs_encoding(); | |
if (isdirsep(*path)) path++; | |
+ if (enc) { | |
+ return chompdirsep_enc(path, path + strlen(path), enc); | |
+ } | |
return chompdirsep(path); | |
} | |
+char * | |
+rb_enc_path_end(const char *path, const char *end, rb_encoding *enc) | |
+{ | |
+ if (isdirsep(*path)) path++; | |
+ return chompdirsep_enc(path, end, enc); | |
+} | |
+ | |
#if USE_NTFS | |
static char * | |
-ntfs_tail(const char *path) | |
+ntfs_tail(const char *path, const char *end, rb_encoding *enc) | |
{ | |
- while (*path == '.') path++; | |
- while (*path && *path != ':') { | |
+ while (path < end && *path == '.') path++; | |
+ while (path < end && *path != ':') { | |
+ const char *last = path; | |
if (istrailinggarbage(*path)) { | |
- const char *last = path++; | |
- while (istrailinggarbage(*path)) path++; | |
- if (!*path || *path == ':') return (char *)last; | |
+ do { | |
+ if (++path >= end || *path == ':') | |
+ return (char *)last; | |
+ } while (istrailinggarbage(*path)); | |
} | |
else if (isdirsep(*path)) { | |
- const char *last = path++; | |
- while (isdirsep(*path)) path++; | |
- if (!*path) return (char *)last; | |
+ do { | |
+ if (++path >= end) return (char *)last; | |
+ } while (isdirsep(*path)); | |
if (*path == ':') path++; | |
} | |
else { | |
- path = CharNext(path); | |
+ Inc(path, end, enc); | |
} | |
} | |
return (char *)path; | |
} | |
+#ifdef __WIN32__ | |
+static int | |
+has_magic(const char *s, const char *e, rb_encoding *enc) | |
+{ | |
+ while (s < e) { | |
+ switch (*s) { | |
+ case '*': | |
+ case '?': | |
+ return 1; | |
+ } | |
+ Inc(s, e, enc); | |
+ } | |
+ | |
+ return 0; | |
+} | |
+#endif | |
#endif | |
@@ -2667,9 +2813,29 @@ ntfs_tail(const char *path) | |
pend = p + buflen) | |
-#define SET_EXTERNAL_ENCODING() (\ | |
- (void)(extenc || (extenc = rb_default_external_encoding())),\ | |
- rb_enc_associate(result, extenc)) | |
+static int is_absolute_path(const char *path, const char *end); | |
-static int is_absolute_path(const char*); | |
+static VALUE | |
+path_encode(VALUE path, rb_encoding *enc) | |
+{ | |
+ rb_encoding *origenc = rb_enc_get(path); | |
+ | |
+ if (enc != origenc) { | |
+ int idx1 = rb_enc_to_index(enc); | |
+ int idx2 = rb_enc_to_index(origenc); | |
+ int ascii8bit = rb_ascii8bit_encindex(); | |
+ int usascii = rb_usascii_encindex(); | |
+ if (idx1 == ascii8bit || idx1 == usascii) { | |
+ rb_enc_associate_index(path, idx2); | |
+ } | |
+ else if (idx2 == ascii8bit || idx2 == usascii) { | |
+ rb_enc_associate_index(path, idx1); | |
+ } | |
+ else { | |
+ VALUE encoded = rb_str_encode(path, rb_enc_from_encoding(enc), 0, Qnil); | |
+ rb_str_shared_replace(path, encoded); | |
+ } | |
+ } | |
+ return path; | |
+} | |
VALUE | |
@@ -2682,4 +2848,5 @@ rb_home_dir(const char *user, VALUE resu | |
#endif | |
long dirlen; | |
+ rb_encoding *enc = rb_enc_get(result); | |
if (!user || !*user) { | |
@@ -2706,6 +2873,8 @@ rb_home_dir(const char *user, VALUE resu | |
#endif | |
} | |
+ rb_enc_associate(result, rb_filesystem_encoding()); | |
+ path_encode(result, enc); | |
#if defined DOSISH || defined __CYGWIN__ | |
- for (p = buf; *p; p = CharNext(p)) { | |
+ for (p = buf; *p; Inc(p, p + rb_enc_mbmaxlen(enc), enc)) { | |
if (*p == '\\') { | |
*p = '/'; | |
@@ -2719,24 +2888,26 @@ static VALUE | |
file_expand_path(VALUE fname, VALUE dname, int abs_mode, VALUE result) | |
{ | |
- const char *s, *b; | |
+ const char *s, *b, *e; | |
char *buf, *p, *pend, *root; | |
size_t buflen, dirlen, bdiff; | |
int tainted; | |
- rb_encoding *extenc = 0; | |
+ rb_encoding *enc; | |
FilePathValue(fname); | |
+ enc = rb_enc_get(fname); | |
s = StringValuePtr(fname); | |
+ e = s + RSTRING_LEN(fname); | |
BUFINIT(); | |
tainted = OBJ_TAINTED(fname); | |
- if (s[0] == '~' && abs_mode == 0) { /* execute only if NOT absolute_path() */ | |
+ if (s < e && s[0] == '~' && abs_mode == 0) { /* execute only if NOT absolute_path() */ | |
tainted = 1; | |
- if (isdirsep(s[1]) || s[1] == '\0') { | |
+ if ((s + 1 == e) || isdirsep(s[1])) { | |
buf = 0; | |
rb_str_set_len(result, 0); | |
- if (*++s) ++s; | |
+ if (++s < e) ++s; | |
} | |
else { | |
- s = nextdirsep(b = s); | |
+ s = rb_enc_path_next(b = s, e, enc); | |
BUFCHECK(bdiff + (s-b) >= buflen); | |
memcpy(p, b, s-b); | |
@@ -2745,4 +2916,5 @@ file_expand_path(VALUE fname, VALUE dnam | |
p += s-b; | |
} | |
+ rb_enc_associate(result, enc); | |
rb_home_dir(buf, result); | |
BUFINIT(); | |
@@ -2751,5 +2923,5 @@ file_expand_path(VALUE fname, VALUE dnam | |
#ifdef DOSISH_DRIVE_LETTER | |
/* skip drive letter */ | |
- else if (has_drive_letter(s)) { | |
+ else if (has_drive_letter2(s, e)) { | |
if (isdirsep(s[2])) { | |
/* specified drive letter, and full path */ | |
@@ -2767,28 +2939,27 @@ file_expand_path(VALUE fname, VALUE dnam | |
file_expand_path(dname, Qnil, abs_mode, result); | |
BUFINIT(); | |
- if (has_drive_letter(p) && TOLOWER(p[0]) == TOLOWER(s[0])) { | |
+ if (has_drive_letter2(p, pend) && TOLOWER(p[0]) == TOLOWER(s[0])) { | |
/* ok, same drive */ | |
same = 1; | |
+ path_encode(result, enc); | |
} | |
} | |
if (!same) { | |
- char *dir = getcwdofdrv(*s); | |
- | |
+ rb_enc_associate(result, enc); | |
+ getcwdofdrv(*s, result); | |
+ BUFINIT(); | |
tainted = 1; | |
- dirlen = strlen(dir); | |
- BUFCHECK(dirlen > buflen); | |
- strcpy(buf, dir); | |
- xfree(dir); | |
- SET_EXTERNAL_ENCODING(); | |
} | |
- p = chompdirsep(skiproot(buf)); | |
+ p = chompdirsep_enc(skiproot(buf, buf + buflen), buf + buflen, enc); | |
s += 2; | |
} | |
} | |
#endif | |
- else if (!is_absolute_path(s)) { | |
+ else if (!is_absolute_path(s, e)) { | |
if (!NIL_P(dname)) { | |
file_expand_path(dname, Qnil, abs_mode, result); | |
+ path_encode(result, enc); | |
BUFINIT(); | |
+ dirlen = buflen; | |
} | |
else { | |
@@ -2800,15 +2971,16 @@ file_expand_path(VALUE fname, VALUE dnam | |
strcpy(buf, dir); | |
xfree(dir); | |
- SET_EXTERNAL_ENCODING(); | |
+ rb_enc_associate(result, rb_filesystem_encoding()); | |
+ path_encode(result, enc); | |
} | |
#if defined DOSISH || defined __CYGWIN__ | |
- if (isdirsep(*s)) { | |
+ if (s < e && isdirsep(*s)) { | |
/* specified full path, but not drive letter nor UNC */ | |
/* we need to get the drive letter or UNC share name */ | |
- p = skipprefix(buf); | |
+ p = rb_enc_path_skip_prefix(buf, buf + dirlen, enc); | |
} | |
else | |
#endif | |
- p = chompdirsep(skiproot(buf)); | |
+ p = chompdirsep_enc(skiproot(buf, buf + dirlen), buf + dirlen, enc); | |
} | |
else { | |
@@ -2828,6 +3000,5 @@ file_expand_path(VALUE fname, VALUE dnam | |
BUFCHECK(bdiff + 1 >= buflen); | |
- p[1] = 0; | |
- root = skipprefix(buf); | |
+ root = rb_enc_path_skip_prefix(buf, p + 1, enc); | |
b = s; | |
@@ -2845,5 +3016,5 @@ file_expand_path(VALUE fname, VALUE dnam | |
char *n; | |
*p = '\0'; | |
- if (!(n = strrdirsep(root))) { | |
+ if (!(n = rb_enc_path_last_separator(root, p, enc))) { | |
*p = '/'; | |
} | |
@@ -2899,5 +3070,5 @@ file_expand_path(VALUE fname, VALUE dnam | |
break; | |
default: | |
- s = CharNext(s); | |
+ Inc(s, e, enc); | |
break; | |
} | |
@@ -2924,9 +3095,9 @@ file_expand_path(VALUE fname, VALUE dnam | |
p += s-b; | |
} | |
- if (p == skiproot(buf) - 1) p++; | |
+ if (p == skiproot(buf, p) - 1) p++; | |
#if USE_NTFS && defined __WIN32__ | |
*p = '\0'; | |
- if ((s = strrdirsep(b = buf)) != 0 && !strpbrk(s, "*?")) { | |
+ if ((s = rb_enc_path_last_separator(b = buf, p, enc)) != 0 && !has_magic(s, e, enc)) { | |
size_t len; | |
WIN32_FIND_DATA wfd; | |
@@ -3103,9 +3274,10 @@ rb_file_s_basename(int argc, VALUE *argv | |
{ | |
VALUE fname, fext, basename; | |
- const char *name, *p; | |
+ const char *name, *p, *end; | |
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC | |
const char *root; | |
#endif | |
long f, n; | |
+ rb_encoding *enc; | |
if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { | |
@@ -3113,7 +3285,9 @@ rb_file_s_basename(int argc, VALUE *argv | |
} | |
FilePathStringValue(fname); | |
- if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname))) | |
+ if ((n = RSTRING_LEN(fname)) == 0 || !*(name = RSTRING_PTR(fname))) | |
return rb_str_new_shared(fname); | |
- name = skipprefix(name); | |
+ end = name + n; | |
+ enc = rb_enc_get(fname); | |
+ name = rb_enc_path_skip_prefix(name, end, enc); | |
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC | |
root = name; | |
@@ -3142,5 +3316,5 @@ rb_file_s_basename(int argc, VALUE *argv | |
} | |
else { | |
- if (!(p = strrdirsep(name))) { | |
+ if (!(p = rb_enc_path_last_separator(name, end, enc))) { | |
p = name; | |
} | |
@@ -3149,7 +3323,7 @@ rb_file_s_basename(int argc, VALUE *argv | |
} | |
#if USE_NTFS | |
- n = ntfs_tail(p) - p; | |
+ n = ntfs_tail(p, end, enc) - p; | |
#else | |
- n = chompdirsep(p) - p; | |
+ n = chompdirsep_enc(p, end, enc) - p; | |
#endif | |
if (NIL_P(fext) || !(f = rmext(p, n, StringValueCStr(fext)))) { | |
@@ -3179,18 +3353,21 @@ static VALUE | |
rb_file_s_dirname(VALUE klass, VALUE fname) | |
{ | |
- const char *name, *root, *p; | |
+ const char *name, *root, *p, *end; | |
VALUE dirname; | |
+ rb_encoding *enc; | |
FilePathStringValue(fname); | |
name = StringValueCStr(fname); | |
- root = skiproot(name); | |
+ end = name + RSTRING_LEN(fname); | |
+ enc = rb_enc_get(fname); | |
+ root = skiproot(name, end); | |
#ifdef DOSISH_UNC | |
if (root > name + 1 && isdirsep(*name)) | |
- root = skipprefix(name = root - 2); | |
+ root = rb_enc_path_skip_prefix(name = root - 2, end, enc); | |
#else | |
if (root > name + 1) | |
name = root - 1; | |
#endif | |
- p = strrdirsep(root); | |
+ p = rb_enc_path_last_separator(root, end, enc); | |
if (!p) { | |
p = root; | |
@@ -3199,6 +3376,6 @@ rb_file_s_dirname(VALUE klass, VALUE fna | |
return rb_usascii_str_new2("."); | |
#ifdef DOSISH_DRIVE_LETTER | |
- if (has_drive_letter(name) && isdirsep(*(name + 2))) { | |
- const char *top = skiproot(name + 2); | |
+ if (name + 2 < end && has_drive_letter(name) && isdirsep(*(name + 2))) { | |
+ const char *top = skiproot(name + 2, end); | |
dirname = rb_str_new(name, 3); | |
rb_str_cat(dirname, top, p - top); | |
@@ -3233,10 +3410,13 @@ static VALUE | |
rb_file_s_extname(VALUE klass, VALUE fname) | |
{ | |
- const char *name, *p, *e; | |
+ const char *name, *p, *e, *end; | |
VALUE extname; | |
+ rb_encoding *enc; | |
FilePathStringValue(fname); | |
name = StringValueCStr(fname); | |
- p = strrdirsep(name); /* get the last path component */ | |
+ end = name + RSTRING_LEN(fname); | |
+ enc = rb_enc_get(fname); | |
+ p = rb_enc_path_last_separator(name, end, enc); | |
if (!p) | |
p = name; | |
@@ -3271,5 +3451,5 @@ rb_file_s_extname(VALUE klass, VALUE fna | |
else if (isdirsep(*p)) | |
break; | |
- p = CharNext(p); | |
+ Inc(p, end, enc); | |
} | |
if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */ | |
@@ -4485,14 +4665,14 @@ rb_file_const(const char *name, VALUE va | |
static int | |
-is_absolute_path(const char *path) | |
+is_absolute_path(const char *path, const char *end) | |
{ | |
#ifdef DOSISH_DRIVE_LETTER | |
- if (has_drive_letter(path) && isdirsep(path[2])) return 1; | |
+ if (path + 2 < end && has_drive_letter(path) && isdirsep(path[2])) return 1; | |
#endif | |
#ifdef DOSISH_UNC | |
- if (isdirsep(path[0]) && isdirsep(path[1])) return 1; | |
+ if (path + 1 < end && isdirsep(path[0]) && isdirsep(path[1])) return 1; | |
#endif | |
#ifndef DOSISH | |
- if (path[0] == '/') return 1; | |
+ if (path < end && path[0] == '/') return 1; | |
#endif | |
return 0; | |
@@ -4513,7 +4693,9 @@ path_check_0(VALUE path, int execpath) | |
struct stat st; | |
const char *p0 = StringValueCStr(path); | |
+ const char *end = p0 + RSTRING_LEN(path); | |
+ rb_encoding *enc = rb_enc_get(path); | |
char *p = 0, *s; | |
- if (!is_absolute_path(p0)) { | |
+ if (!is_absolute_path(p0, end)) { | |
char *buf = my_getcwd(); | |
VALUE newpath; | |
@@ -4540,6 +4722,9 @@ path_check_0(VALUE path, int execpath) | |
return 0; | |
} | |
- s = strrdirsep(p0); | |
- if (p) *p = '/'; | |
+ if (p) { | |
+ *p = '/'; | |
+ end = p; | |
+ } | |
+ s = rb_enc_path_last_separator(p0, end, enc); | |
if (!s || s == p0) return 1; | |
p = s; | |
@@ -4570,16 +4755,12 @@ rb_path_check(const char *path) | |
pend = path + strlen(path); | |
p0 = path; | |
- p = strchr(path, sep); | |
- if (!p) p = pend; | |
- | |
- for (;;) { | |
+ do { | |
+ p = memchr(p0, sep, pend - p0); | |
+ if (!p) p = pend; | |
if (!path_check_0(rb_str_new(p0, p - p0), TRUE)) { | |
return 0; /* not safe */ | |
} | |
p0 = p + 1; | |
- if (p0 > pend) break; | |
- p = strchr(p0, sep); | |
- if (!p) p = pend; | |
- } | |
+ } while (p0 < pend); | |
#endif | |
return 1; | |
@@ -4611,9 +4792,9 @@ rb_file_load_ok(const char *path) | |
static int | |
-is_explicit_relative(const char *path) | |
+is_explicit_relative(const char *path, const char *end) | |
{ | |
- if (*path++ != '.') return 0; | |
- if (*path == '.') path++; | |
- return isdirsep(*path); | |
+ if (path >= end || *path++ != '.') return 0; | |
+ if (path >= end || *path == '.') path++; | |
+ return path < end && isdirsep(*path); | |
} | |
@@ -4639,4 +4820,6 @@ rb_find_file_ext_safe(VALUE *filep, cons | |
const char *f = StringValueCStr(*filep); | |
VALUE fname = *filep, load_path, tmp; | |
+ const char *e = f + RSTRING_LEN(fname); | |
+ rb_encoding *enc = rb_enc_get(fname); | |
long i, j, fnlen; | |
int expanded = 0; | |
@@ -4644,5 +4827,5 @@ rb_find_file_ext_safe(VALUE *filep, cons | |
if (!ext[0]) return 0; | |
- if (f[0] == '~') { | |
+ if (f < e && f[0] == '~') { | |
fname = rb_file_expand_path(*filep, Qnil); | |
if (safe_level >= 1 && OBJ_TAINTED(fname)) { | |
@@ -4650,9 +4833,11 @@ rb_find_file_ext_safe(VALUE *filep, cons | |
} | |
f = RSTRING_PTR(fname); | |
+ e = f + RSTRING_LEN(fname); | |
+ enc = rb_enc_get(fname); | |
*filep = fname; | |
expanded = 1; | |
} | |
- if (expanded || is_absolute_path(f) || is_explicit_relative(f)) { | |
+ if (expanded || is_absolute_path(f, e) || is_explicit_relative(f, e)) { | |
if (safe_level >= 1 && !fpath_check(f)) { | |
rb_raise(rb_eSecurityError, "loading from unsafe path %s", f); | |
@@ -4713,7 +4898,9 @@ rb_find_file_safe(VALUE path, int safe_l | |
VALUE tmp, load_path; | |
const char *f = StringValueCStr(path); | |
+ const char *e = f + RSTRING_LEN(path); | |
+ rb_encoding *enc = rb_enc_get(path); | |
int expanded = 0; | |
- if (f[0] == '~') { | |
+ if (f < e && f[0] == '~') { | |
tmp = rb_file_expand_path(path, Qnil); | |
if (safe_level >= 1 && OBJ_TAINTED(tmp)) { | |
@@ -4722,8 +4909,10 @@ rb_find_file_safe(VALUE path, int safe_l | |
path = copy_path_class(tmp, path); | |
f = RSTRING_PTR(path); | |
+ e = f + RSTRING_LEN(path); | |
+ enc = rb_enc_get(path); | |
expanded = 1; | |
} | |
- if (expanded || is_absolute_path(f) || is_explicit_relative(f)) { | |
+ if (expanded || is_absolute_path(f, e) || is_explicit_relative(f, e)) { | |
if (safe_level >= 1 && !fpath_check(f)) { | |
rb_raise(rb_eSecurityError, "loading from unsafe path %s", f); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment