win32.c: readlink
* win32/win32.c (wreadlink, rb_w32_ureadlink): implement readlink(). git-svn-id: svn+ssh://ci.ruby-lang.org/ruby/trunk@50062 b2dd03c8-39d4-4d8f-98ff-823fe69b080e
This commit is contained in:
parent
d503d6c7ae
commit
c57932f782
@ -1,3 +1,7 @@
|
|||||||
|
Mon Mar 23 17:36:00 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
||||||
|
|
||||||
|
* win32/win32.c (wreadlink, rb_w32_ureadlink): implement readlink().
|
||||||
|
|
||||||
Mon Mar 23 14:40:45 2015 Nobuyoshi Nakada <nobu@ruby-lang.org>
|
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_stat): stat with following symbolic links.
|
||||||
|
@ -1104,6 +1104,7 @@ main()
|
|||||||
ac_cv_func_isnan=yes
|
ac_cv_func_isnan=yes
|
||||||
ac_cv_func_finite=yes
|
ac_cv_func_finite=yes
|
||||||
ac_cv_func_link=yes
|
ac_cv_func_link=yes
|
||||||
|
ac_cv_func_readlink=yes
|
||||||
ac_cv_lib_crypt_crypt=no
|
ac_cv_lib_crypt_crypt=no
|
||||||
ac_cv_func_getpgrp_void=no
|
ac_cv_func_getpgrp_void=no
|
||||||
ac_cv_func_memcmp_working=yes
|
ac_cv_func_memcmp_working=yes
|
||||||
|
@ -316,6 +316,9 @@ extern int chown(const char *, int, int);
|
|||||||
extern int rb_w32_uchown(const char *, int, int);
|
extern int rb_w32_uchown(const char *, int, int);
|
||||||
extern int link(const char *, const char *);
|
extern int link(const char *, const char *);
|
||||||
extern int rb_w32_ulink(const char *, const char *);
|
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 gettimeofday(struct timeval *, struct timezone *);
|
extern int gettimeofday(struct timeval *, struct timezone *);
|
||||||
extern int clock_gettime(clockid_t, struct timespec *);
|
extern int clock_gettime(clockid_t, struct timespec *);
|
||||||
extern int clock_getres(clockid_t, struct timespec *);
|
extern int clock_getres(clockid_t, struct timespec *);
|
||||||
|
@ -712,6 +712,7 @@ $(CONFIG_H): $(MKFILES) $(srcdir)/win32/Makefile.sub $(win_srcdir)/Makefile.sub
|
|||||||
#define HAVE_TIMES 1
|
#define HAVE_TIMES 1
|
||||||
#define HAVE_FCNTL 1
|
#define HAVE_FCNTL 1
|
||||||
#define HAVE_LINK 1
|
#define HAVE_LINK 1
|
||||||
|
#define HAVE_READLINK 1
|
||||||
#define HAVE__SETJMP 1
|
#define HAVE__SETJMP 1
|
||||||
#define HAVE_TELLDIR 1
|
#define HAVE_TELLDIR 1
|
||||||
#define HAVE_SEEKDIR 1
|
#define HAVE_SEEKDIR 1
|
||||||
|
110
win32/win32.c
110
win32/win32.c
@ -4678,6 +4678,116 @@ link(const char *from, const char *to)
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* License: Ruby's */
|
||||||
|
ssize_t
|
||||||
|
rb_w32_wreadlink(const WCHAR *path, WCHAR *buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
struct {
|
||||||
|
ULONG ReparseTag;
|
||||||
|
USHORT ReparseDataLength;
|
||||||
|
USHORT Reserved;
|
||||||
|
struct {
|
||||||
|
USHORT SubstituteNameOffset;
|
||||||
|
USHORT SubstituteNameLength;
|
||||||
|
USHORT PrintNameOffset;
|
||||||
|
USHORT PrintNameLength;
|
||||||
|
ULONG Flags;
|
||||||
|
WCHAR PathBuffer[MAXPATHLEN * 2];
|
||||||
|
} SymbolicLinkReparseBuffer;
|
||||||
|
} rp;
|
||||||
|
HANDLE f;
|
||||||
|
DWORD ret;
|
||||||
|
int e = 0;
|
||||||
|
|
||||||
|
typedef BOOL (WINAPI *device_io_control_func)(HANDLE, DWORD, LPVOID,
|
||||||
|
DWORD, LPVOID, DWORD,
|
||||||
|
LPDWORD, LPOVERLAPPED);
|
||||||
|
static device_io_control_func device_io_control = (device_io_control_func)-1;
|
||||||
|
|
||||||
|
if (device_io_control == (device_io_control_func)-1) {
|
||||||
|
device_io_control = (device_io_control_func)
|
||||||
|
get_proc_address("kernel32", "DeviceIoControl", NULL);
|
||||||
|
}
|
||||||
|
if (!device_io_control) {
|
||||||
|
errno = ENOSYS;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = CreateFileW(path, 0, FILE_SHARE_READ|FILE_SHARE_WRITE,
|
||||||
|
NULL, OPEN_EXISTING,
|
||||||
|
FILE_FLAG_BACKUP_SEMANTICS|FILE_FLAG_OPEN_REPARSE_POINT,
|
||||||
|
NULL);
|
||||||
|
if (f == INVALID_HANDLE_VALUE) {
|
||||||
|
errno = map_errno(GetLastError());
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!device_io_control(f, FSCTL_GET_REPARSE_POINT, NULL, 0,
|
||||||
|
&rp, sizeof(rp), &ret, NULL)) {
|
||||||
|
e = map_errno(GetLastError());
|
||||||
|
}
|
||||||
|
else if (rp.ReparseTag != IO_REPARSE_TAG_SYMLINK){
|
||||||
|
e = EINVAL;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
void *name = ((char *)rp.SymbolicLinkReparseBuffer.PathBuffer +
|
||||||
|
rp.SymbolicLinkReparseBuffer.PrintNameOffset);
|
||||||
|
ret = rp.SymbolicLinkReparseBuffer.PrintNameLength;
|
||||||
|
((WCHAR *)name)[ret/sizeof(WCHAR)] = L'\0';
|
||||||
|
translate_wchar(name, L'\\', L'/');
|
||||||
|
bufsize *= sizeof(WCHAR);
|
||||||
|
memcpy(buf, name, ret > bufsize ? bufsize : ret);
|
||||||
|
}
|
||||||
|
|
||||||
|
CloseHandle(f);
|
||||||
|
if (e) {
|
||||||
|
errno = e;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return ret / sizeof(WCHAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* License: Ruby's */
|
||||||
|
static ssize_t
|
||||||
|
w32_readlink(UINT cp, const char *path, char *buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
WCHAR *wpath;
|
||||||
|
WCHAR wbuf[MAXPATHLEN];
|
||||||
|
ssize_t ret;
|
||||||
|
|
||||||
|
wpath = mbstr_to_wstr(cp, path, -1, NULL);
|
||||||
|
if (!wpath) return -1;
|
||||||
|
ret = rb_w32_wreadlink(wpath, wbuf, MAXPATHLEN);
|
||||||
|
free(wpath);
|
||||||
|
if (ret < 0) return ret;
|
||||||
|
ret = WideCharToMultiByte(cp, 0, wbuf, ret, buf, bufsize, NULL, NULL);
|
||||||
|
if (!ret) {
|
||||||
|
int e = GetLastError();
|
||||||
|
if (e == ERROR_INSUFFICIENT_BUFFER) {
|
||||||
|
ret = bufsize;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
errno = map_errno(e);
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* License: Ruby's */
|
||||||
|
ssize_t
|
||||||
|
rb_w32_ureadlink(const char *path, char *buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
return w32_readlink(CP_UTF8, path, buf, bufsize);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* License: Ruby's */
|
||||||
|
ssize_t
|
||||||
|
readlink(const char *path, char *buf, size_t bufsize)
|
||||||
|
{
|
||||||
|
return w32_readlink(filecp(), path, buf, bufsize);
|
||||||
|
}
|
||||||
|
|
||||||
/* License: Ruby's */
|
/* License: Ruby's */
|
||||||
int
|
int
|
||||||
wait(int *status)
|
wait(int *status)
|
||||||
|
Loading…
x
Reference in New Issue
Block a user