Skip to content

Instantly share code, notes, and snippets.

@nobu
Created October 7, 2009 15:08
Show Gist options
  • Save nobu/204118 to your computer and use it in GitHub Desktop.
Save nobu/204118 to your computer and use it in GitHub Desktop.
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