summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authornobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-08-24 21:34:45 +0000
committernobu <nobu@b2dd03c8-39d4-4d8f-98ff-823fe69b080e>2015-08-24 21:34:45 +0000
commit2e5c105ff23f2f3304060a6493f29d92a7b692f3 (patch)
treee8c2ce5c55aee7ffde3c876d320262b46db4c8bb
parent457ca4dc29d9047e7547a02acb73845edce606a3 (diff)
win32.c: symlink
* win32/win32.c (w32_symlink): implement symlink(). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@51674 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
-rw-r--r--ChangeLog4
-rw-r--r--configure.in1
-rw-r--r--file.c2
-rw-r--r--include/ruby/win32.h2
-rw-r--r--win32/Makefile.sub1
-rw-r--r--win32/win32.c63
6 files changed, 73 insertions, 0 deletions
diff --git a/ChangeLog b/ChangeLog
index 7b3478ed2c..e0fa5542c2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+Tue Aug 25 06:34:43 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
+
+ * win32/win32.c (w32_symlink): implement symlink().
+
Mon Aug 24 16:01:19 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
* encoding.c (rb_locale_encindex): find encoding index without
diff --git a/configure.in b/configure.in
index c0f960bd56..a46f6b60c6 100644
--- a/configure.in
+++ b/configure.in
@@ -1108,6 +1108,7 @@ main()
ac_cv_func_finite=yes
ac_cv_func_link=yes
ac_cv_func_readlink=yes
+ ac_cv_func_symlink=yes
ac_cv_lib_crypt_crypt=no
ac_cv_func_getpgrp_void=no
ac_cv_func_memcmp_working=yes
diff --git a/file.c b/file.c
index 48c978ed36..9472d43319 100644
--- a/file.c
+++ b/file.c
@@ -111,6 +111,8 @@ int flock(int, int);
#define unlink(p) rb_w32_uunlink(p)
#undef rename
#define rename(f, t) rb_w32_urename((f), (t))
+#undef symlink
+#define symlink(s, l) rb_w32_usymlink((s), (l))
#else
#define STAT(p, s) stat((p), (s))
#endif
diff --git a/include/ruby/win32.h b/include/ruby/win32.h
index 7bf389d8e1..e6bc077206 100644
--- a/include/ruby/win32.h
+++ b/include/ruby/win32.h
@@ -289,6 +289,8 @@ extern int rb_w32_ulink(const char *, const char *);
extern ssize_t readlink(const char *, char *, size_t);
extern ssize_t rb_w32_ureadlink(const char *, char *, size_t);
extern ssize_t rb_w32_wreadlink(const WCHAR *, WCHAR *, size_t);
+extern int symlink(const char *src, const char *link);
+extern int rb_w32_usymlink(const char *src, const char *link);
extern int gettimeofday(struct timeval *, struct timezone *);
extern int clock_gettime(clockid_t, struct timespec *);
extern int clock_getres(clockid_t, struct timespec *);
diff --git a/win32/Makefile.sub b/win32/Makefile.sub
index 741c0cff4d..ab7e6fe046 100644
--- a/win32/Makefile.sub
+++ b/win32/Makefile.sub
@@ -719,6 +719,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
#define HAVE_FCNTL 1
#define HAVE_LINK 1
#define HAVE_READLINK 1
+#define HAVE_SYMLINK 1
#define HAVE__SETJMP 1
#define HAVE_TELLDIR 1
#define HAVE_SEEKDIR 1
diff --git a/win32/win32.c b/win32/win32.c
index ae99612cb1..beea93871e 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -210,6 +210,7 @@ static struct {
{ ERROR_OPERATION_ABORTED, EINTR },
{ ERROR_NOT_ENOUGH_QUOTA, ENOMEM },
{ ERROR_MOD_NOT_FOUND, ENOENT },
+ { ERROR_PRIVILEGE_NOT_HELD, EACCES, },
{ WSAEINTR, EINTR },
{ WSAEBADF, EBADF },
{ WSAEACCES, EACCES },
@@ -4815,6 +4816,68 @@ readlink(const char *path, char *buf, size_t bufsize)
return w32_readlink(filecp(), path, buf, bufsize);
}
+#ifndef SYMBOLIC_LINK_FLAG_DIRECTORY
+#define SYMBOLIC_LINK_FLAG_DIRECTORY (0x1)
+#endif
+
+/* License: Ruby's */
+static int
+w32_symlink(UINT cp, const char *src, const char *link)
+{
+ int atts, len1, len2;
+ VALUE buf;
+ WCHAR *wsrc, *wlink;
+ DWORD flag = 0;
+ BOOLEAN ret;
+
+ typedef DWORD (WINAPI *create_symbolic_link_func)(WCHAR*, WCHAR*, DWORD);
+ static create_symbolic_link_func create_symbolic_link =
+ (create_symbolic_link_func)-1;
+
+ if (create_symbolic_link == (create_symbolic_link_func)-1) {
+ create_symbolic_link = (create_symbolic_link_func)
+ get_proc_address("kernel32", "CreateSymbolicLinkW", NULL);
+ }
+ if (!create_symbolic_link) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ len1 = MultiByteToWideChar(cp, 0, src, -1, NULL, 0);
+ len2 = MultiByteToWideChar(cp, 0, link, -1, NULL, 0);
+ wsrc = ALLOCV_N(WCHAR, buf, len1+len2);
+ wlink = wsrc + len1;
+ MultiByteToWideChar(cp, 0, src, -1, wsrc, len1);
+ MultiByteToWideChar(cp, 0, link, -1, wlink, len2);
+
+ atts = GetFileAttributesW(wsrc);
+ if (atts != -1 && atts & FILE_ATTRIBUTE_DIRECTORY)
+ flag = SYMBOLIC_LINK_FLAG_DIRECTORY;
+ ret = create_symbolic_link(wlink, wsrc, flag);
+ ALLOCV_END(buf);
+
+ if (!ret) {
+ int e = GetLastError();
+ errno = map_errno(e);
+ return -1;
+ }
+ return 0;
+}
+
+/* License: Ruby's */
+int
+rb_w32_usymlink(const char *src, const char *link)
+{
+ return w32_symlink(CP_UTF8, src, link);
+}
+
+/* License: Ruby's */
+int
+symlink(const char *src, const char *link)
+{
+ return w32_symlink(filecp(), src, link);
+}
+
/* License: Ruby's */
int
wait(int *status)