summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-07-02 10:14:05 +0000
committeryugui <yugui@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2010-07-02 10:14:05 +0000
commitec4ca0fcbb406e10bc00be01e376a32bd87af88c (patch)
tree59ac15259e17064fe000aba9fa784ebefe6e155d
parent318deef393dd9f7e66f7c548b12d53e24a877600 (diff)
* io.c (argf_inplace_mode_set): prohibits an assignment
of a tainted value. Patch by unak. * util.c, file.c: prevents a buffer over-run on windows. Patch by unak. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_9_2@28522 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog8
-rw-r--r--file.c151
-rw-r--r--io.c3
-rw-r--r--util.c97
-rw-r--r--version.h4
5 files changed, 166 insertions, 97 deletions
diff --git a/ChangeLog b/ChangeLog
index 106c2e2dfc..7a41e1d610 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+Fri Jul 2 19:07:09 2010 Yuki Sonoda (Yugui) <yugui@yugui.jp>
+
+ * io.c (argf_inplace_mode_set): prohibits an assignment
+ of a tainted value. Patch by unak.
+
+ * util.c, file.c: prevents a buffer over-run on windows.
+ Patch by unak.
+
Tue Jun 29 19:39:59 2010 Masaki Suketa <masaki.suketa@nifty.ne.jp>
* test/win32ole/test_win32ole_method.rb (is_ruby64): check
diff --git a/file.c b/file.c
index cd69a587aa..46cf319ff7 100644
--- a/file.c
+++ b/file.c
@@ -3429,42 +3429,15 @@ rmext(const char *p, long l1, const char *e)
return 0;
}
-/*
- * call-seq:
- * File.basename(file_name [, suffix] ) -> base_name
- *
- * Returns the last component of the filename given in <i>file_name</i>,
- * which must be formed using forward slashes (``<code>/</code>'')
- * regardless of the separator used on the local file system. If
- * <i>suffix</i> is given and present at the end of <i>file_name</i>,
- * it is removed.
- *
- * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
- * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
- */
-
-static VALUE
-rb_file_s_basename(int argc, VALUE *argv)
+const char *
+ruby_find_basename(const char *name, long *len, long *ext)
{
- VALUE fname, fext, basename;
- const char *name, *p;
+ const char *p;
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
const char *root;
#endif
- long f, n;
+ long f, n = -1;
- if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
- rb_encoding *enc;
- StringValue(fext);
- if (!rb_enc_asciicompat(enc = rb_enc_get(fext))) {
- rb_raise(rb_eEncCompatError, "ascii incompatible character encodings: %s",
- rb_enc_name(enc));
- }
- }
- FilePathStringValue(fname);
- if (!NIL_P(fext)) rb_enc_check(fname, fext);
- if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname)))
- return rb_str_new_shared(fname);
name = skipprefix(name);
#if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC
root = name;
@@ -3503,11 +3476,57 @@ rb_file_s_basename(int argc, VALUE *argv)
#else
n = chompdirsep(p) - p;
#endif
+ }
+
+ if (len)
+ *len = f;
+ if (ext)
+ *ext = n;
+ return p;
+}
+
+/*
+ * call-seq:
+ * File.basename(file_name [, suffix] ) -> base_name
+ *
+ * Returns the last component of the filename given in <i>file_name</i>,
+ * which must be formed using forward slashes (``<code>/</code>'')
+ * regardless of the separator used on the local file system. If
+ * <i>suffix</i> is given and present at the end of <i>file_name</i>,
+ * it is removed.
+ *
+ * File.basename("/home/gumby/work/ruby.rb") #=> "ruby.rb"
+ * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby"
+ */
+
+static VALUE
+rb_file_s_basename(int argc, VALUE *argv)
+{
+ VALUE fname, fext, basename;
+ const char *name, *p;
+ long f, n;
+
+ if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) {
+ rb_encoding *enc;
+ StringValue(fext);
+ if (!rb_enc_asciicompat(enc = rb_enc_get(fext))) {
+ rb_raise(rb_eEncCompatError, "ascii incompatible character encodings: %s",
+ rb_enc_name(enc));
+ }
+ }
+ FilePathStringValue(fname);
+ if (!NIL_P(fext)) rb_enc_check(fname, fext);
+ if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname)))
+ return rb_str_new_shared(fname);
+
+ p = ruby_find_basename(name, &f, &n);
+ if (n >= 0) {
if (NIL_P(fext) || !(f = rmext(p, n, StringValueCStr(fext)))) {
f = n;
}
if (f == RSTRING_LEN(fname)) return rb_str_new_shared(fname);
}
+
basename = rb_str_new(p, f);
rb_enc_copy(basename, fname);
OBJ_INFECT(basename, fname);
@@ -3573,27 +3592,22 @@ rb_file_dirname(VALUE fname)
}
/*
- * call-seq:
- * File.extname(path) -> string
- *
- * Returns the extension (the portion of file name in <i>path</i>
- * after the period).
- *
- * File.extname("test.rb") #=> ".rb"
- * File.extname("a/b/d/test.rb") #=> ".rb"
- * File.extname("test") #=> ""
- * File.extname(".profile") #=> ""
+ * accept a String, and return the pointer of the extension.
+ * if len is passed, set the length of extension to it.
+ * returned pointer is in ``name'' or NULL.
+ * returns *len
+ * no dot NULL 0
+ * dotfile top 0
+ * end with dot dot 1
+ * .ext dot len of .ext
+ * .ext:stream dot len of .ext without :stream (NT only)
*
*/
-
-static VALUE
-rb_file_s_extname(VALUE klass, VALUE fname)
+const char *
+ruby_find_extname(const char *name, long *len)
{
- const char *name, *p, *e;
- VALUE extname;
+ const char *p, *e;
- FilePathStringValue(fname);
- name = StringValueCStr(fname);
p = strrdirsep(name); /* get the last path component */
if (!p)
p = name;
@@ -3629,9 +3643,46 @@ rb_file_s_extname(VALUE klass, VALUE fname)
break;
p = CharNext(p);
}
- if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */
+
+ if (len) {
+ /* no dot, or the only dot is first or end? */
+ if (!e || e == name)
+ *len = 0;
+ else if (e+1 == p)
+ *len = 1;
+ else
+ *len = p - e;
+ }
+ return e;
+}
+
+/*
+ * call-seq:
+ * File.extname(path) -> string
+ *
+ * Returns the extension (the portion of file name in <i>path</i>
+ * after the period).
+ *
+ * File.extname("test.rb") #=> ".rb"
+ * File.extname("a/b/d/test.rb") #=> ".rb"
+ * File.extname("test") #=> ""
+ * File.extname(".profile") #=> ""
+ *
+ */
+
+static VALUE
+rb_file_s_extname(VALUE klass, VALUE fname)
+{
+ const char *name, *e;
+ long len;
+ VALUE extname;
+
+ FilePathStringValue(fname);
+ name = StringValueCStr(fname);
+ e = ruby_find_extname(name, &len);
+ if (len <= 1)
return rb_str_new(0, 0);
- extname = rb_str_new(e, p - e); /* keep the dot, too! */
+ extname = rb_str_new(e, len); /* keep the dot, too! */
rb_enc_copy(extname, fname);
OBJ_INFECT(extname, fname);
return extname;
diff --git a/io.c b/io.c
index 5d6d162c11..077d1c036e 100644
--- a/io.c
+++ b/io.c
@@ -9548,6 +9548,9 @@ opt_i_get(ID id, VALUE *var)
static VALUE
argf_inplace_mode_set(VALUE argf, VALUE val)
{
+ if (rb_safe_level() >= 1 && OBJ_TAINTED(val))
+ rb_insecure_operation();
+
if (!RTEST(val)) {
if (ARGF.inplace) free(ARGF.inplace);
ARGF.inplace = 0;
diff --git a/util.c b/util.c
index 2f67107691..368558607f 100644
--- a/util.c
+++ b/util.c
@@ -258,77 +258,85 @@ static int valid_filename(const char *s);
static const char suffix1[] = ".$$$";
static const char suffix2[] = ".~~~";
-#define ext (&buf[1000])
-
#define strEQ(s1,s2) (strcmp(s1,s2) == 0)
+extern const char *ruby_find_basename(const char *, long *, long *);
+extern const char *ruby_find_extname(const char *, long *);
+
void
ruby_add_suffix(VALUE str, const char *suffix)
{
int baselen;
int extlen = strlen(suffix);
- char *s, *t, *p;
+ char *p, *q;
long slen;
char buf[1024];
- char *const bufend = buf + sizeof(buf);
+ const char *name;
+ const char *ext;
+ long len;
- if (RSTRING_LEN(str) > 1000)
- rb_fatal("Cannot do inplace edit on long filename (%ld characters)",
- RSTRING_LEN(str));
+ name = StringValueCStr(str);
+ slen = strlen(name);
+ if (slen > sizeof(buf) - 1)
+ rb_fatal("Cannot do inplace edit on long filename (%ld characters)",
+ slen);
-#if defined(__CYGWIN32__) || defined(_WIN32)
/* Style 0 */
- slen = RSTRING_LEN(str);
rb_str_cat(str, suffix, extlen);
if (valid_filename(RSTRING_PTR(str))) return;
/* Fooey, style 0 failed. Fix str before continuing. */
rb_str_resize(str, slen);
-#endif
-
- slen = extlen;
- t = buf; baselen = 0; s = RSTRING_PTR(str);
- while ((*t = *s) && *s != '.') {
- baselen++;
- if (*s == '\\' || *s == '/') baselen = 0;
- s++; t++;
- }
- p = t;
-
- t = ext; extlen = 0;
- while ((*t++ = *s++) != 0) extlen++;
- if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; }
+ name = StringValueCStr(str);
+ ext = ruby_find_extname(name, &len);
if (*suffix == '.') { /* Style 1 */
- if (strEQ(ext, suffix)) goto fallback;
- strlcpy(p, suffix, bufend - p);
- }
- else if (suffix[1] == '\0') { /* Style 2 */
- if (extlen < 4) {
- ext[extlen] = *suffix;
- ext[++extlen] = '\0';
- }
- else if (baselen < 8) {
- *p++ = *suffix;
+ if (ext) {
+ if (strEQ(ext, suffix)) goto fallback;
+ slen = ext - name;
}
- else if (ext[3] != *suffix) {
- ext[3] = *suffix;
+ rb_str_resize(str, slen);
+ rb_str_cat(str, suffix, extlen);
+ }
+ else {
+ strncpy(buf, name, slen);
+ if (ext)
+ p = buf + (ext - name);
+ else
+ p = buf + slen;
+ p[len] = '\0';
+ if (suffix[1] == '\0') { /* Style 2 */
+ if (len <= 3) {
+ p[len] = *suffix;
+ p[++len] = '\0';
+ }
+ else if ((q = (char *)ruby_find_basename(buf, &baselen, 0)) &&
+ baselen < 8) {
+ q += baselen;
+ *q++ = *suffix;
+ if (ext) {
+ strncpy(q, ext, ext - name);
+ q[ext - name + 1] = '\0';
+ }
+ else
+ *q = '\0';
+ }
+ else if (len == 4 && p[3] != *suffix)
+ p[3] = *suffix;
+ else if (baselen == 8 && q[7] != *suffix)
+ q[7] = *suffix;
+ else
+ goto fallback;
}
- else if (buf[7] != *suffix) {
- buf[7] = *suffix;
+ else { /* Style 3: Panic */
+ fallback:
+ (void)memcpy(p, !ext || strEQ(ext, suffix1) ? suffix2 : suffix1, 5);
}
- else goto fallback;
- strlcpy(p, ext, bufend - p);
- }
- else { /* Style 3: Panic */
-fallback:
- (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5);
}
rb_str_resize(str, strlen(buf));
memcpy(RSTRING_PTR(str), buf, RSTRING_LEN(str));
}
-#if defined(__CYGWIN32__) || defined(_WIN32)
static int
valid_filename(const char *s)
{
@@ -350,7 +358,6 @@ valid_filename(const char *s)
return 0;
}
#endif
-#endif
/* mm.c */
diff --git a/version.h b/version.h
index 1a1294a6b5..48737c4f1d 100644
--- a/version.h
+++ b/version.h
@@ -1,5 +1,5 @@
#define RUBY_VERSION "1.9.2"
-#define RUBY_RELEASE_DATE "2010-07-01"
+#define RUBY_RELEASE_DATE "2010-07-02"
#define RUBY_PATCHLEVEL -1
#define RUBY_VERSION_MAJOR 1
@@ -7,7 +7,7 @@
#define RUBY_VERSION_TEENY 1
#define RUBY_RELEASE_YEAR 2010
#define RUBY_RELEASE_MONTH 7
-#define RUBY_RELEASE_DAY 1
+#define RUBY_RELEASE_DAY 2
#include "ruby/version.h"