From d5e7bf424e08f21a6dbc6291e50590a969c6f6db Mon Sep 17 00:00:00 2001 From: shyouhei Date: Mon, 22 Nov 2010 07:21:34 +0000 Subject: Fri, 2 Jul 2010 14:35:10 +0000 usa merge revision(s) 28525:28568: * file.c (ruby_find_basename, ruby_find_extname): split from rb_file_s_basename() and rb_file_s_extname(). * util.c (ruby_add_suffix): support arbitrary length of the suffix to get rid of the potential buffer overflow. reported by tarui. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@28526 b2dd03c8-39d4-4d8f-98ff-823fe69b080e Signed-off-by: URABE, Shyouhei merge from trunk (r28565) * file.c (ruby_find_basename): set correct baselen. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@28566 b2dd03c8-39d4-4d8f-98ff-823fe69b080e Signed-off-by: URABE, Shyouhei merge from trunk (r28565) * file.c (ruby_find_basename): set correct baselen. git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8@28568 b2dd03c8-39d4-4d8f-98ff-823fe69b080e Signed-off-by: URABE, Shyouhei git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/branches/ruby_1_8_7@29855 b2dd03c8-39d4-4d8f-98ff-823fe69b080e --- ChangeLog | 13 ++++++ file.c | 141 +++++++++++++++++++++++++++++++++++++++++++++++--------------- util.c | 108 ++++++++++++++++++++++++----------------------- version.h | 2 +- 4 files changed, 178 insertions(+), 86 deletions(-) diff --git a/ChangeLog b/ChangeLog index 5d7da7d685..793de828fa 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,16 @@ +Wed Jul 7 13:24:24 2010 NAKAMURA Usaku + + * file.c (ruby_find_basename): set correct baselen. + +Fri Jul 2 23:34:45 2010 NAKAMURA Usaku + + * file.c (ruby_find_basename, ruby_find_extname): split from + rb_file_s_basename() and rb_file_s_extname(). + + * util.c (ruby_add_suffix): support arbitrary length of the suffix + to get rid of the potential buffer overflow. + reported by tarui. + Sat Jul 10 10:51:29 2010 KOSAKI Motohiro * configure.in: fix use_context condition inversion. diff --git a/file.c b/file.c index 9452d046d9..1bb3364daa 100644 --- a/file.c +++ b/file.c @@ -2881,24 +2881,17 @@ rmext(p, l1, e) * File.basename("/home/gumby/work/ruby.rb", ".rb") #=> "ruby" */ -static VALUE -rb_file_s_basename(argc, argv) - int argc; - VALUE *argv; +const char * +ruby_find_basename(name, baselen, alllen) + const char *name; + long *baselen, *alllen; { - VALUE fname, fext, basename; - const char *name, *p; + const char *p, *q, *e; #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC const char *root; #endif - int f, n; + long f = 0, n = -1; - if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { - StringValue(fext); - } - StringValue(fname); - if (RSTRING(fname)->len == 0 || !*(name = RSTRING(fname)->ptr)) - return fname; name = skipprefix(name); #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC root = name; @@ -2937,11 +2930,59 @@ rb_file_s_basename(argc, argv) #else n = chompdirsep(p) - p; #endif + for (q = p; q - p < n && *q == '.'; q++); + for (e = 0; q - p < n; q = CharNext(q)) { + if (*q == '.') e = q; + } + if (e) f = e - p; + else f = n; + } + + if (baselen) + *baselen = f; + if (alllen) + *alllen = n; + return p; +} + +/* + * call-seq: + * File.basename(file_name [, suffix] ) -> base_name + * + * Returns the last component of the filename given in file_name, + * which must be formed using forward slashes (``/'') + * regardless of the separator used on the local file system. If + * suffix is given and present at the end of file_name, + * 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(argc, argv) + 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) { + StringValue(fext); + } + StringValue(fname); + if (RSTRING_LEN(fname) == 0 || !*(name = RSTRING_PTR(fname))) + return 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 fname; } + basename = rb_str_new(p, f); OBJ_INFECT(basename, fname); return basename; @@ -2999,27 +3040,24 @@ rb_file_s_dirname(klass, fname) } /* - * call-seq: - * File.extname(path) -> string - * - * Returns the extension (the portion of file name in path - * 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(klass, fname) - VALUE klass, fname; +const char * +ruby_find_extname(name, len) + const char *name; + long *len; { - const char *name, *p, *e; - VALUE extname; + const char *p, *e; - name = StringValueCStr(fname); p = strrdirsep(name); /* get the last path component */ if (!p) p = name; @@ -3054,9 +3092,46 @@ rb_file_s_extname(klass, 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 path + * 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(klass, fname) + VALUE klass, fname; +{ + const char *name, *e; + long len; + VALUE extname; + + 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! */ OBJ_INFECT(extname, fname); return extname; } diff --git a/util.c b/util.c index 961aaba4c7..62f33683ab 100644 --- a/util.c +++ b/util.c @@ -155,79 +155,83 @@ static int valid_filename(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(str, suffix) - VALUE str; - char *suffix; +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]; + const char *name; + const char *ext; + long len; - if (RSTRING(str)->len > 1000) - rb_fatal("Cannot do inplace edit on long filename (%ld characters)", - RSTRING(str)->len); + 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(DJGPP) || defined(__CYGWIN32__) || defined(_WIN32) /* Style 0 */ - slen = RSTRING(str)->len; rb_str_cat(str, suffix, extlen); -#if defined(DJGPP) - if (_USE_LFN) return; -#else - if (valid_filename(RSTRING(str)->ptr)) return; -#endif + if (valid_filename(RSTRING_PTR(str))) return; /* Fooey, style 0 failed. Fix str before continuing. */ - RSTRING(str)->ptr[RSTRING(str)->len = slen] = '\0'; -#endif - - slen = extlen; - t = buf; baselen = 0; s = RSTRING(str)->ptr; - while ((*t = *s) && *s != '.') { - baselen++; - if (*s == '\\' || *s == '/') baselen = 0; - s++; t++; - } - p = t; - - t = ext; extlen = 0; - while (*t++ = *s++) extlen++; - if (extlen == 0) { ext[0] = '.'; ext[1] = 0; extlen++; } + rb_str_resize(str, slen); + name = StringValueCStr(str); + ext = ruby_find_extname(name, &len); if (*suffix == '.') { /* Style 1 */ - if (strEQ(ext, suffix)) goto fallback; - strcpy(p, suffix); - } - 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; - strcpy(p, ext); - } - else { /* Style 3: Panic */ -fallback: - (void)memcpy(p, strEQ(ext, suffix1) ? suffix2 : suffix1, 5); } rb_str_resize(str, strlen(buf)); - memcpy(RSTRING(str)->ptr, buf, RSTRING(str)->len); + memcpy(RSTRING_PTR(str), buf, RSTRING_LEN(str)); } #if defined(__CYGWIN32__) || defined(_WIN32) diff --git a/version.h b/version.h index 0a9ae3abc2..f93577a7cf 100644 --- a/version.h +++ b/version.h @@ -2,7 +2,7 @@ #define RUBY_RELEASE_DATE "2010-11-22" #define RUBY_VERSION_CODE 187 #define RUBY_RELEASE_CODE 20101122 -#define RUBY_PATCHLEVEL 304 +#define RUBY_PATCHLEVEL 305 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 -- cgit v1.2.3