aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog7
-rw-r--r--configure.in1
-rw-r--r--dir.c2
-rw-r--r--file.c2
-rw-r--r--include/ruby/win32.h3
-rw-r--r--win32/Makefile.sub1
-rw-r--r--win32/win32.c101
7 files changed, 115 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index 465ce345f1..b18f1e5f9a 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,10 @@
+Mon Mar 23 14:40:45 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (winnt_stat): stat with following symbolic links.
+
+ * win32/win32.c (winnt_lstat): rename old winnt_stat, which does
+ not follow symbolic links.
+
Mon Mar 23 02:03:28 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* marshal.c (r_symreal): register symbol names as strings first so
diff --git a/configure.in b/configure.in
index 21ea2f70fd..d9b4f72e7b 100644
--- a/configure.in
+++ b/configure.in
@@ -1094,6 +1094,7 @@ main()
ac_cv_header_sys_time_h=no
ac_cv_header_sys_times_h=no
ac_cv_header_sys_socket_h=no
+ ac_cv_func_lstat=yes
ac_cv_func_times=yes
ac_cv_func_waitpid=yes
ac_cv_func_fsync=yes
diff --git a/dir.c b/dir.c
index d5b12402a9..9fbbcb1ebb 100644
--- a/dir.c
+++ b/dir.c
@@ -1135,6 +1135,8 @@ sys_enc_warning_in(const char *func, const char *mesg, rb_encoding *enc)
#ifdef _WIN32
#define STAT(p, s) rb_w32_ustati64((p), (s))
+#undef lstat
+#define lstat(p, s) rb_w32_ulstati64((p), (s))
#else
#define STAT(p, s) stat((p), (s))
#endif
diff --git a/file.c b/file.c
index 44cf4ae3bf..bd8aeec784 100644
--- a/file.c
+++ b/file.c
@@ -95,7 +95,7 @@ int flock(int, int);
#ifdef _WIN32
#define STAT(p, s) rb_w32_ustati64((p), (s))
#undef lstat
-#define lstat(p, s) rb_w32_ustati64((p), (s))
+#define lstat(p, s) rb_w32_ulstati64((p), (s))
#undef access
#define access(p, m) rb_w32_uaccess((p), (m))
#undef chmod
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index eaf7363237..88416e9e08 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -215,6 +215,7 @@ typedef int clockid_t;
extern int rb_w32_stat(const char *, struct stat *);
extern int rb_w32_fstat(int, struct stat *);
#endif
+#define lstat(path,st) rb_w32_lstati64(path,st)
#define access(path,mode) rb_w32_access(path,mode)
#define strcasecmp _stricmp
@@ -343,6 +344,8 @@ extern int rb_w32_uunlink(const char *);
extern int rb_w32_uchmod(const char *, int);
extern int rb_w32_stati64(const char *, struct stati64 *);
extern int rb_w32_ustati64(const char *, struct stati64 *);
+extern int rb_w32_lstati64(const char *, struct stati64 *);
+extern int rb_w32_ulstati64(const char *, struct stati64 *);
extern int rb_w32_access(const char *, int);
extern int rb_w32_uaccess(const char *, int);
extern char rb_w32_fd_is_text(int);
diff --git a/win32/Makefile.sub b/win32/Makefile.sub
index 56cd86a14c..259193e0b2 100644
--- a/win32/Makefile.sub
+++ b/win32/Makefile.sub
@@ -708,6 +708,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define HAVE_GETCWD 1
#define HAVE_TRUNCATE 1
#define HAVE_FTRUNCATE 1
+#define HAVE_LSTAT 1
#define HAVE_TIMES 1
#define HAVE_FCNTL 1
#define HAVE_LINK 1
diff --git a/win32/win32.c b/win32/win32.c
index 30b7e27fa0..a8ef299cc5 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -61,6 +61,7 @@ DWORD WINAPI GetFinalPathNameByHandleW(HANDLE, LPWSTR, DWORD, DWORD);
#endif
static int w32_stati64(const char *path, struct stati64 *st, UINT cp);
+static int w32_lstati64(const char *path, struct stati64 *st, UINT cp);
static char *w32_getenv(const char *name, UINT cp);
#undef getenv
@@ -111,6 +112,7 @@ static int has_redirection(const char *, UINT);
int rb_w32_wait_events(HANDLE *events, int num, DWORD timeout);
static int rb_w32_open_osfhandle(intptr_t osfhandle, int flags);
static int wstati64(const WCHAR *path, struct stati64 *st);
+static int wlstati64(const WCHAR *path, struct stati64 *st);
VALUE rb_w32_conv_from_wchar(const WCHAR *wstr, rb_encoding *enc);
int ruby_brace_glob_with_enc(const char *str, int flags, ruby_glob_func *func, VALUE arg, rb_encoding *enc);
@@ -5079,17 +5081,63 @@ path_drive(const WCHAR *path)
towupper(path[0]) - L'A' : _getdrive() - 1;
}
+static const WCHAR namespace_prefix[] = {L'\\', L'\\', L'?', L'\\'};
+
/* License: Ruby's */
static int
winnt_stat(const WCHAR *path, struct stati64 *st)
{
+ HANDLE f;
+
+ typedef DWORD (WINAPI *get_final_path_func)(HANDLE, WCHAR*, DWORD, DWORD);
+ static get_final_path_func get_final_path = (get_final_path_func)-1;
+
+ if (get_final_path == (get_final_path_func)-1) {
+ get_final_path = (get_final_path_func)
+ get_proc_address(NULL, "GetFinalPathNameByHandleW", NULL);
+ }
+
+ memset(st, 0, sizeof(*st));
+ f = CreateFileW(path, 0, 0, NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS, NULL);
+ if (f != INVALID_HANDLE_VALUE) {
+ WCHAR finalname[MAX_PATH];
+ const DWORD attr = stati64_handle(f, st);
+ const DWORD len = get_final_path ?
+ get_final_path(f, finalname, numberof(finalname), 0) : 0;
+ CloseHandle(f);
+ if (attr & FILE_ATTRIBUTE_DIRECTORY) {
+ if (check_valid_dir(path)) return -1;
+ }
+ st->st_mode = fileattr_to_unixmode(attr, path);
+ if (len) {
+ finalname[len] = L'\0';
+ path = finalname;
+ if (wcsncmp(path, namespace_prefix, numberof(namespace_prefix)) == 0)
+ path += numberof(namespace_prefix);
+ }
+ }
+ else {
+ if (stat_by_find(path, st)) return -1;
+ }
+
+ st->st_dev = st->st_rdev = path_drive(path);
+
+ return 0;
+}
+
+/* License: Ruby's */
+static int
+winnt_lstat(const WCHAR *path, struct stati64 *st)
+{
WIN32_FILE_ATTRIBUTE_DATA wfa;
const WCHAR *p = path;
memset(st, 0, sizeof(*st));
st->st_nlink = 1;
- if (wcsncmp(p, L"\\\\?\\", 4) == 0) p += 4;
+ if (wcsncmp(p, namespace_prefix, numberof(namespace_prefix)) == 0)
+ p += numberof(namespace_prefix);
if (wcspbrk(p, L"?*")) {
errno = ENOENT;
return -1;
@@ -5151,6 +5199,29 @@ wstati64(const WCHAR *path, struct stati64 *st)
}
/* License: Ruby's */
+static int
+wlstati64(const WCHAR *path, struct stati64 *st)
+{
+ WCHAR *buf1;
+ int ret, size;
+ VALUE v;
+
+ if (!path || !st) {
+ errno = EFAULT;
+ return -1;
+ }
+ size = lstrlenW(path) + 2;
+ buf1 = ALLOCV_N(WCHAR, v, size);
+ if (!(path = name_for_stat(buf1, path)))
+ return -1;
+ ret = winnt_lstat(path, st);
+ if (v)
+ ALLOCV_END(v);
+
+ return ret;
+}
+
+/* License: Ruby's */
static WCHAR *
name_for_stat(WCHAR *buf1, const WCHAR *path)
{
@@ -5214,6 +5285,34 @@ w32_stati64(const char *path, struct stati64 *st, UINT cp)
/* License: Ruby's */
int
+rb_w32_ulstati64(const char *path, struct stati64 *st)
+{
+ return w32_lstati64(path, st, CP_UTF8);
+}
+
+/* License: Ruby's */
+int
+rb_w32_lstati64(const char *path, struct stati64 *st)
+{
+ return w32_lstati64(path, st, filecp());
+}
+
+/* License: Ruby's */
+static int
+w32_lstati64(const char *path, struct stati64 *st, UINT cp)
+{
+ WCHAR *wpath;
+ int ret;
+
+ if (!(wpath = mbstr_to_wstr(cp, path, -1, NULL)))
+ return -1;
+ ret = wlstati64(wpath, st);
+ free(wpath);
+ return ret;
+}
+
+/* License: Ruby's */
+int
rb_w32_access(const char *path, int mode)
{
struct stati64 stat;