ruby-changes:4949
From: ko1@a...
Date: Sat, 17 May 2008 12:16:07 +0900 (JST)
Subject: [ruby-changes:4949] nobu - Ruby:r16442 (ruby_1_8_6, ruby_1_8_5): * file.c (file_expand_path): support for alternative data stream
nobu 2008-05-17 12:15:54 +0900 (Sat, 17 May 2008) New Revision: 16442 Modified files: branches/ruby_1_8_5/ChangeLog branches/ruby_1_8_5/file.c branches/ruby_1_8_5/version.h branches/ruby_1_8_6/ChangeLog branches/ruby_1_8_6/file.c branches/ruby_1_8_6/version.h Log: * file.c (file_expand_path): support for alternative data stream and ignored trailing garbages of NTFS. * file.c (rb_file_s_basename): ditto. * file.c (rb_file_s_extname): ditto. http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_6/ChangeLog?r1=16442&r2=16441&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_6/version.h?r1=16442&r2=16441&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_6/file.c?r1=16442&r2=16441&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_5/version.h?r1=16442&r2=16441&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_5/ChangeLog?r1=16442&r2=16441&diff_format=u http://svn.ruby-lang.org/cgi-bin/viewvc.cgi/branches/ruby_1_8_5/file.c?r1=16442&r2=16441&diff_format=u Index: ruby_1_8_5/ChangeLog =================================================================== --- ruby_1_8_5/ChangeLog (revision 16441) +++ ruby_1_8_5/ChangeLog (revision 16442) @@ -1,3 +1,12 @@ +Sat May 17 12:15:48 2008 Nobuyoshi Nakada <nobu@r...> + + * file.c (file_expand_path): support for alternative data stream + and ignored trailing garbages of NTFS. + + * file.c (rb_file_s_basename): ditto. + + * file.c (rb_file_s_extname): ditto. + Mon Mar 3 23:36:41 2008 GOTOU Yuuzou <gotoyuzo@n...> * lib/webrick/httpservlet/filehandler.rb: should normalize path Index: ruby_1_8_5/version.h =================================================================== --- ruby_1_8_5/version.h (revision 16441) +++ ruby_1_8_5/version.h (revision 16442) @@ -1,15 +1,15 @@ #define RUBY_VERSION "1.8.5" -#define RUBY_RELEASE_DATE "2008-03-03" +#define RUBY_RELEASE_DATE "2008-05-17" #define RUBY_VERSION_CODE 185 -#define RUBY_RELEASE_CODE 20080303 +#define RUBY_RELEASE_CODE 20080517 #define RUBY_PATCHLEVEL 115 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 #define RUBY_VERSION_TEENY 5 #define RUBY_RELEASE_YEAR 2008 -#define RUBY_RELEASE_MONTH 3 -#define RUBY_RELEASE_DAY 3 +#define RUBY_RELEASE_MONTH 5 +#define RUBY_RELEASE_DAY 17 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; Index: ruby_1_8_5/file.c =================================================================== --- ruby_1_8_5/file.c (revision 16441) +++ ruby_1_8_5/file.c (revision 16442) @@ -15,6 +15,10 @@ #ifdef _WIN32 #include "missing/file.h" #endif +#ifdef __CYGWIN__ +#include <windows.h> +#include <sys/cygwin.h> +#endif #include "ruby.h" #include "rubyio.h" @@ -2304,8 +2308,20 @@ # else # define CharNext(p) ((p) + 1) # endif +#if defined _WIN32 || defined __CYGWIN__ +#define USE_NTFS 1 +#else +#define USE_NTFS 0 #endif +#if USE_NTFS +#define istrailinggabage(x) ((x) == '.' || (x) == ' ') +#else +#define istrailinggabage(x) 0 +#endif + +#endif + #ifdef __CYGWIN__ #undef DOSISH #define DOSISH_UNC @@ -2441,6 +2457,30 @@ return (char *)path; } +#if USE_NTFS +static char * +ntfs_tail(const char *path) +{ + while (*path && *path != ':') { + if (istrailinggabage(*path)) { + const char *last = path++; + while (istrailinggabage(*path)) path++; + if (!*path || *path == ':') return (char *)last; + } + else if (isdirsep(*path)) { + const char *last = path++; + while (isdirsep(*path)) path++; + if (!*path) return (char *)last; + if (*path == ':') path++; + } + else { + path = CharNext(path); + } + } + return (char *)path; +} +#endif + #define BUFCHECK(cond) do {\ long bdiff = p - buf;\ while (cond) {\ @@ -2467,7 +2507,8 @@ file_expand_path(fname, dname, result) VALUE fname, dname, result; { - char *s, *buf, *b, *p, *pend, *root; + const char *s, *b; + char *buf, *p, *pend, *root; long buflen, dirlen; int tainted; @@ -2608,15 +2649,21 @@ case '.': if (*(s+1) == '\0' || isdirsep(*(s+1))) { /* We must go back to the parent */ + char *n; *p = '\0'; - if (!(b = strrdirsep(root))) { + if (!(n = strrdirsep(root))) { *p = '/'; } else { - p = b; + p = n; } b = ++s; } +#if USE_NTFS + else { + do *++s; while (istrailinggabage(*s)); + } +#endif break; case '/': #if defined DOSISH || defined __CYGWIN__ @@ -2629,6 +2676,19 @@ break; } } +#if USE_NTFS + else { + --s; + case ' ': { + const char *e = s; + while (istrailinggabage(*s)) s++; + if (!*s) { + s = e; + goto endpath; + } + } + } +#endif break; case '/': #if defined DOSISH || defined __CYGWIN__ @@ -2651,15 +2711,75 @@ } if (s > b) { +#if USE_NTFS + endpath: + if (s > b + 6 && strncasecmp(s - 6, ":$DATA", 6) == 0) { + /* alias of stream */ + /* get rid of a bug of x64 VC++ */ + if (*(s-7) == ':') s -= 7; /* prime */ + else if (memchr(b, ':', s - 6 - b)) s -= 6; /* alternative */ + } +#endif BUFCHECK(bdiff + (s-b) >= buflen); memcpy(++p, b, s-b); p += s-b; } if (p == skiproot(buf) - 1) p++; + buflen = p - buf; +#if USE_NTFS + *p = '\0'; + if (!strpbrk(b = buf, "*?")) { + size_t len; + WIN32_FIND_DATA wfd; +#ifdef __CYGWIN__ + int lnk_added = 0; + struct stat st; + char w32buf[MAXPATHLEN], sep = 0; + p = 0; + if (lstat(buf, &st) == 0 && S_ISLNK(st.st_mode)) { + p = strrdirsep(buf); + if (!p) p = skipprefix(buf); + if (p) { + sep = *p; + *p = '\0'; + } + } + if (cygwin_conv_to_win32_path(buf, w32buf) == 0) { + b = w32buf; + } + if (p) *p = sep; + else p = buf; + if (b == w32buf) { + strlcat(w32buf, p, sizeof(w32buf)); + len = strlen(p); + if (len > 4 && strcasecmp(p + len - 4, ".lnk") != 0) { + lnk_added = 1; + strlcat(w32buf, ".lnk", sizeof(w32buf)); + } + } +#endif + HANDLE h = FindFirstFile(b, &wfd); + if (h != INVALID_HANDLE_VALUE) { + FindClose(h); + p = strrdirsep(buf); + len = strlen(wfd.cFileName); +#ifdef __CYGWIN__ + if (lnk_added && len > 4 && + strcasecmp(wfd.cFileName + len - 4, ".lnk") == 0) { + len -= 4; + } +#endif + if (!p) p = buf; + buflen = ++p - buf + len; + rb_str_resize(result, buflen); + memcpy(p, wfd.cFileName, len + 1); + } + } +#endif + if (tainted) OBJ_TAINT(result); - RSTRING(result)->len = p - buf; - *p = '\0'; + rb_str_set_len(result, buflen); return result; } @@ -2703,18 +2823,21 @@ } static int -rmext(p, e) +rmext(p, l1, e) const char *p, *e; + int l1; { - int l1, l2; + int l2; if (!e) return 0; - l1 = chompdirsep(p) - p; l2 = strlen(e); if (l2 == 2 && e[1] == '*') { - e = strrchr(p, *e); - if (!e) return 0; + unsigned char c = *e; + e = p + l1; + do { + if (e <= p) return 0; + } while (*--e != c); return e - p; } if (l1 < l2) return l1; @@ -2749,7 +2872,7 @@ #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC char *root; #endif - int f; + int f, n; if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { StringValue(fext); @@ -2783,18 +2906,22 @@ #endif #endif } - else if (!(p = strrdirsep(name))) { - if (NIL_P(fext) || !(f = rmext(name, StringValueCStr(fext)))) { - f = chompdirsep(name) - name; - if (f == RSTRING(fname)->len) return fname; - } - p = name; - } else { - while (isdirsep(*p)) p++; /* skip last / */ - if (NIL_P(fext) || !(f = rmext(p, StringValueCStr(fext)))) { - f = chompdirsep(p) - p; + if (!(p = strrdirsep(name))) { + p = name; } + else { + while (isdirsep(*p)) p++; /* skip last / */ + } +#if USE_NTFS + n = ntfs_tail(p) - p; +#else + n = chompdirsep(p) - p; +#endif + 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); @@ -2869,22 +2996,49 @@ rb_file_s_extname(klass, fname) VALUE klass, fname; { - char *name, *p, *e; + const char *name, *p, *e; VALUE extname; name = StringValueCStr(fname); p = strrdirsep(name); /* get the last path component */ if (!p) - p = name; + p = name; else - p++; - - e = strrchr(p, '.'); /* get the last dot of the last component */ - if (!e || e == p || !e[1]) /* no dot, or the only dot is first or end? */ - return rb_str_new2(""); - extname = rb_str_new(e, chompdirsep(e) - e); /* keep the dot, too! */ - OBJ_INFECT(extname, fname); - return extname; + name = ++p; + + e = 0; + while (*p) { + if (*p == '.' || istrailinggabage(*p)) { +#if USE_NTFS + const char *last = p++, *dot = last; + while (istrailinggabage(*p)) { + if (*p == '.') dot = p; + p++; + } + if (!*p || *p == ':') { + p = last; + break; + } + e = dot; + continue; +#else + e = p; /* get the last dot of the last component */ +#endif + } +#if USE_NTFS + else if (*p == ':') { + break; + } +#endif + else if (isdirsep(*p)) + break; + p = CharNext(p); + } + if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */ + return rb_str_new(0, 0); + extname = rb_str_new(e, p - e); /* keep the dot, too! */ + OBJ_INFECT(extname, fname); + return extname; } /* Index: ruby_1_8_6/ChangeLog =================================================================== --- ruby_1_8_6/ChangeLog (revision 16441) +++ ruby_1_8_6/ChangeLog (revision 16442) @@ -1,3 +1,12 @@ +Sat May 17 12:15:48 2008 Nobuyoshi Nakada <nobu@r...> + + * file.c (file_expand_path): support for alternative data stream + and ignored trailing garbages of NTFS. + + * file.c (rb_file_s_basename): ditto. + + * file.c (rb_file_s_extname): ditto. + Mon Mar 3 23:34:13 2008 GOTOU Yuuzou <gotoyuzo@n...> * lib/webrick/httpservlet/filehandler.rb: should normalize path Index: ruby_1_8_6/version.h =================================================================== --- ruby_1_8_6/version.h (revision 16441) +++ ruby_1_8_6/version.h (revision 16442) @@ -1,15 +1,15 @@ #define RUBY_VERSION "1.8.6" -#define RUBY_RELEASE_DATE "2008-03-03" +#define RUBY_RELEASE_DATE "2008-05-17" #define RUBY_VERSION_CODE 186 -#define RUBY_RELEASE_CODE 20080303 +#define RUBY_RELEASE_CODE 20080517 #define RUBY_PATCHLEVEL 114 #define RUBY_VERSION_MAJOR 1 #define RUBY_VERSION_MINOR 8 #define RUBY_VERSION_TEENY 6 #define RUBY_RELEASE_YEAR 2008 -#define RUBY_RELEASE_MONTH 3 -#define RUBY_RELEASE_DAY 3 +#define RUBY_RELEASE_MONTH 5 +#define RUBY_RELEASE_DAY 17 #ifdef RUBY_EXTERN RUBY_EXTERN const char ruby_version[]; Index: ruby_1_8_6/file.c =================================================================== --- ruby_1_8_6/file.c (revision 16441) +++ ruby_1_8_6/file.c (revision 16442) @@ -15,6 +15,10 @@ #ifdef _WIN32 #include "missing/file.h" #endif +#ifdef __CYGWIN__ +#include <windows.h> +#include <sys/cygwin.h> +#endif #include "ruby.h" #include "rubyio.h" @@ -2310,8 +2314,20 @@ # else # define CharNext(p) ((p) + 1) # endif +#if defined _WIN32 || defined __CYGWIN__ +#define USE_NTFS 1 +#else +#define USE_NTFS 0 #endif +#if USE_NTFS +#define istrailinggabage(x) ((x) == '.' || (x) == ' ') +#else +#define istrailinggabage(x) 0 +#endif + +#endif + #ifdef __CYGWIN__ #undef DOSISH #define DOSISH_UNC @@ -2454,6 +2470,30 @@ return chompdirsep(path); } +#if USE_NTFS +static char * +ntfs_tail(const char *path) +{ + while (*path && *path != ':') { + if (istrailinggabage(*path)) { + const char *last = path++; + while (istrailinggabage(*path)) path++; + if (!*path || *path == ':') return (char *)last; + } + else if (isdirsep(*path)) { + const char *last = path++; + while (isdirsep(*path)) path++; + if (!*path) return (char *)last; + if (*path == ':') path++; + } + else { + path = CharNext(path); + } + } + return (char *)path; +} +#endif + #define BUFCHECK(cond) do {\ long bdiff = p - buf;\ while (cond) {\ @@ -2480,7 +2520,8 @@ file_expand_path(fname, dname, result) VALUE fname, dname, result; { - char *s, *buf, *b, *p, *pend, *root; + const char *s, *b; + char *buf, *p, *pend, *root; long buflen, dirlen; int tainted; @@ -2621,15 +2662,21 @@ case '.': if (*(s+1) == '\0' || isdirsep(*(s+1))) { /* We must go back to the parent */ + char *n; *p = '\0'; - if (!(b = strrdirsep(root))) { + if (!(n = strrdirsep(root))) { *p = '/'; } else { - p = b; + p = n; } b = ++s; } +#if USE_NTFS + else { + do *++s; while (istrailinggabage(*s)); + } +#endif break; case '/': #if defined DOSISH || defined __CYGWIN__ @@ -2642,6 +2689,19 @@ break; } } +#if USE_NTFS + else { + --s; + case ' ': { + const char *e = s; + while (istrailinggabage(*s)) s++; + if (!*s) { + s = e; + goto endpath; + } + } + } +#endif break; case '/': #if defined DOSISH || defined __CYGWIN__ @@ -2664,15 +2724,75 @@ } if (s > b) { +#if USE_NTFS + endpath: + if (s > b + 6 && strncasecmp(s - 6, ":$DATA", 6) == 0) { + /* alias of stream */ + /* get rid of a bug of x64 VC++ */ + if (*(s-7) == ':') s -= 7; /* prime */ + else if (memchr(b, ':', s - 6 - b)) s -= 6; /* alternative */ + } +#endif BUFCHECK(bdiff + (s-b) >= buflen); memcpy(++p, b, s-b); p += s-b; } if (p == skiproot(buf) - 1) p++; + buflen = p - buf; +#if USE_NTFS + *p = '\0'; + if (!strpbrk(b = buf, "*?")) { + size_t len; + WIN32_FIND_DATA wfd; +#ifdef __CYGWIN__ + int lnk_added = 0; + struct stat st; + char w32buf[MAXPATHLEN], sep = 0; + p = 0; + if (lstat(buf, &st) == 0 && S_ISLNK(st.st_mode)) { + p = strrdirsep(buf); + if (!p) p = skipprefix(buf); + if (p) { + sep = *p; + *p = '\0'; + } + } + if (cygwin_conv_to_win32_path(buf, w32buf) == 0) { + b = w32buf; + } + if (p) *p = sep; + else p = buf; + if (b == w32buf) { + strlcat(w32buf, p, sizeof(w32buf)); + len = strlen(p); + if (len > 4 && strcasecmp(p + len - 4, ".lnk") != 0) { + lnk_added = 1; + strlcat(w32buf, ".lnk", sizeof(w32buf)); + } + } +#endif + HANDLE h = FindFirstFile(b, &wfd); + if (h != INVALID_HANDLE_VALUE) { + FindClose(h); + p = strrdirsep(buf); + len = strlen(wfd.cFileName); +#ifdef __CYGWIN__ + if (lnk_added && len > 4 && + strcasecmp(wfd.cFileName + len - 4, ".lnk") == 0) { + len -= 4; + } +#endif + if (!p) p = buf; + buflen = ++p - buf + len; + rb_str_resize(result, buflen); + memcpy(p, wfd.cFileName, len + 1); + } + } +#endif + if (tainted) OBJ_TAINT(result); - RSTRING(result)->len = p - buf; - *p = '\0'; + rb_str_set_len(result, buflen); return result; } @@ -2716,18 +2836,21 @@ } static int -rmext(p, e) +rmext(p, l1, e) const char *p, *e; + int l1; { - int l1, l2; + int l2; if (!e) return 0; - l1 = chompdirsep(p) - p; l2 = strlen(e); if (l2 == 2 && e[1] == '*') { - e = strrchr(p, *e); - if (!e) return 0; + unsigned char c = *e; + e = p + l1; + do { + if (e <= p) return 0; + } while (*--e != c); return e - p; } if (l1 < l2) return l1; @@ -2762,7 +2885,7 @@ #if defined DOSISH_DRIVE_LETTER || defined DOSISH_UNC char *root; #endif - int f; + int f, n; if (rb_scan_args(argc, argv, "11", &fname, &fext) == 2) { StringValue(fext); @@ -2796,18 +2919,22 @@ #endif #endif } - else if (!(p = strrdirsep(name))) { - if (NIL_P(fext) || !(f = rmext(name, StringValueCStr(fext)))) { - f = chompdirsep(name) - name; - if (f == RSTRING(fname)->len) return fname; - } - p = name; - } else { - while (isdirsep(*p)) p++; /* skip last / */ - if (NIL_P(fext) || !(f = rmext(p, StringValueCStr(fext)))) { - f = chompdirsep(p) - p; + if (!(p = strrdirsep(name))) { + p = name; } + else { + while (isdirsep(*p)) p++; /* skip last / */ + } +#if USE_NTFS + n = ntfs_tail(p) - p; +#else + n = chompdirsep(p) - p; +#endif + 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); @@ -2883,22 +3010,49 @@ rb_file_s_extname(klass, fname) VALUE klass, fname; { - char *name, *p, *e; + const char *name, *p, *e; VALUE extname; name = StringValueCStr(fname); p = strrdirsep(name); /* get the last path component */ if (!p) - p = name; + p = name; else - p++; - - e = strrchr(p, '.'); /* get the last dot of the last component */ - if (!e || e == p || !e[1]) /* no dot, or the only dot is first or end? */ - return rb_str_new2(""); - extname = rb_str_new(e, chompdirsep(e) - e); /* keep the dot, too! */ - OBJ_INFECT(extname, fname); - return extname; + name = ++p; + + e = 0; + while (*p) { + if (*p == '.' || istrailinggabage(*p)) { +#if USE_NTFS + const char *last = p++, *dot = last; + while (istrailinggabage(*p)) { + if (*p == '.') dot = p; + p++; + } + if (!*p || *p == ':') { + p = last; + break; + } + e = dot; + continue; +#else + e = p; /* get the last dot of the last component */ +#endif + } +#if USE_NTFS + else if (*p == ':') { + break; + } +#endif + else if (isdirsep(*p)) + break; + p = CharNext(p); + } + if (!e || e == name || e+1 == p) /* no dot, or the only dot is first or end? */ + return rb_str_new(0, 0); + extname = rb_str_new(e, p - e); /* keep the dot, too! */ + OBJ_INFECT(extname, fname); + return extname; } /* -- ML: ruby-changes@q... Info: http://www.atdot.net/~ko1/quickml/