This is a combination of 3 patches that have been lost in merges.
Add symlink support; with UAC, you may need administrator's privileges
to create symlinks, but you can at least read them.
As reparse points on Windows differentiate between file and directory
links, we just assume that file links are meant for the time being;
it might be very hard to determine the type before the target exists,
but it is thinkable to change the type on-the-fly.
A bridge to cross when we arrive there (read: something for somebody
to fix who actually has that problem).
Original added by: Johannes Schindelin <johannes....@gmx.de>
Support for utf8 in symlinks.
Copied from work added by Johannes Schindelin <johannes....@gmx.de>
Replace dir separator in symlinks
It seems quite a few windows utilities cannot handle '../' in symlinks, so
we replace every / with a \.
Replace make_backslash_path with a thread-safe version.
original by: Thorvald Natvig <sli...@users.sourceforge.net>
Signed-off-by: Michael Geddes <mic...@frog.wheelycreek.net>
---
compat/mingw.c | 93 ++++++++++++++++++++++++++++++++++++++++++++++++++++++--
compat/mingw.h | 6 +--
2 files changed, 92 insertions(+), 7 deletions(-)
diff --git a/compat/mingw.c b/compat/mingw.c
index 7050a1e..b3f0003 100644
--- a/compat/mingw.c
+++ b/compat/mingw.c
@@ -1,6 +1,7 @@
#include "../git-compat-util.h"
#include "win32.h"
#include <conio.h>
+#include <winioctl.h>
#include <wchar.h>
#include "../strbuf.h"
#include "../cache.h"
@@ -423,6 +424,47 @@ static inline time_t filetime_to_time_t(const FILETIME *ft)
return (time_t)(filetime_to_hnsec(ft) / 10000000);
}
+#ifndef FSCTL_GET_REPARSE_POINT
+#define FSCTL_GET_REPARSE_POINT 0x000900a8
+#endif
+
+static int do_readlink(const wchar_t *path, wchar_t *buf, size_t bufsiz)
+{
+ HANDLE handle = CreateFileW(path, GENERIC_READ,
+ FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
+ NULL, OPEN_EXISTING,
+ FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OPEN_REPARSE_POINT,
+ NULL);
+
+ if (handle != INVALID_HANDLE_VALUE) {
+ unsigned char buffer[MAXIMUM_REPARSE_DATA_BUFFER_SIZE];
+ DWORD dummy = 0;
+ if (DeviceIoControl(handle, FSCTL_GET_REPARSE_POINT, NULL, 0, buffer,
+ MAXIMUM_REPARSE_DATA_BUFFER_SIZE, &dummy, NULL)) {
+ REPARSE_DATA_BUFFER *b = (REPARSE_DATA_BUFFER *) buffer;
+ if (b->ReparseTag == IO_REPARSE_TAG_SYMLINK) {
+ int len = b->SymbolicLinkReparseBuffer.SubstituteNameLength / sizeof(wchar_t);
+ int offset = b->SymbolicLinkReparseBuffer.SubstituteNameOffset / sizeof(wchar_t);
+ int i;
+ len = (bufsiz < len) ? bufsiz : len;
+ wcsncpy(buf, & b->SymbolicLinkReparseBuffer.PathBuffer[offset], len);
+ for (i = 0; i < len; i++)
+ if (buf[i] == '\\')
+ buf[i] = '/';
+ buf[len] = 0;
+ CloseHandle(handle);
+ return len;
+ }
+ }
+
+ CloseHandle(handle);
+ }
+
+ errno = EINVAL;
+ return -1;
+}
+
+
/* We keep the do_lstat code in a separate function to avoid recursion.
* When a path ends with a slash, the stat will fail with ENOENT. In
* this case, we strip the trailing slashes and stat again.
@@ -1767,9 +1809,8 @@ sig_handler_t mingw_signal(int sig, sig_handler_t handler)
return old;
}
-static const char *make_backslash_path(const char *path)
+static const char *make_backslash_path(const char *path, char *buf)
{
- static char buf[PATH_MAX + 1];
char *c;
if (strlcpy(buf, path, PATH_MAX) >= PATH_MAX)
@@ -1784,7 +1825,8 @@ static const char *make_backslash_path(const char *path)
void mingw_open_html(const char *unixpath)
{
- const char *htmlpath = make_backslash_path(unixpath);
+ char buf[PATH_MAX + 1];
+ const char *htmlpath = make_backslash_path(unixpath, buf);
typedef HINSTANCE (WINAPI *T)(HWND, const char *,
const char *, const char *, const char *, INT);
T ShellExecute;
@@ -1834,6 +1876,51 @@ int link(const char *oldpath, const char *newpath)
return 0;
}
+int symlink(const char *oldpath, const char *newpath)
+{
+ typedef BOOL WINAPI (*symlink_fn)(const wchar_t*, const wchar_t*, DWORD);
+ static symlink_fn create_symbolic_link = NULL;
+ char buf[PATH_MAX + 1];
+ wchar_t woldpath[MAX_PATH], wnewpath[MAX_PATH];
+
+ if (utftowcs(woldpath, make_backslash_path(oldpath, buf), MAX_PATH) < 0)
+ return -1;
+ if (utftowcs(wnewpath, newpath, MAX_PATH) < 0)
+ return -1;
+
+ if (!create_symbolic_link) {
+ create_symbolic_link = (symlink_fn) GetProcAddress(
+ GetModuleHandle("kernel32.dll"), "CreateSymbolicLinkW");
+ if (!create_symbolic_link)
+ create_symbolic_link = (symlink_fn)-1;
+ }
+ if (create_symbolic_link == (symlink_fn)-1) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ if (!create_symbolic_link(wnewpath, woldpath, 0)) {
+ errno = err_win_to_posix(GetLastError());
+ return -1;
+ }
+ return 0;
+}
+
+int do_readlink(const wchar_t *path, wchar_t *buf, size_t bufsiz);
+
+int readlink(const char *path, char *buf, size_t bufsiz)
+{
+ wchar_t wpath[MAX_PATH], wbuffer[MAX_PATH];
+ int result;
+ if (utftowcs(wpath, path, MAX_PATH) < 0)
+ return -1;
+ result = do_readlink(wpath, wbuffer, MAX_PATH);
+ if (result >= 0) {
+ return wcstoutf(buf, wbuffer, bufsiz);
+ }
+ return -1;
+}
+
char *getpass(const char *prompt)
{
struct strbuf buf = STRBUF_INIT;
diff --git a/compat/mingw.h b/compat/mingw.h
index afb7faf..5bb9008 100644
--- a/compat/mingw.h
+++ b/compat/mingw.h
@@ -79,10 +79,6 @@ struct itimerval {
* trivial stubs
*/
-static inline int readlink(const char *path, char *buf, size_t bufsiz)
-{ errno = ENOSYS; return -1; }
-static inline int symlink(const char *oldpath, const char *newpath)
-{ errno = ENOSYS; return -1; }
static inline int fchmod(int fildes, mode_t mode)
{ errno = ENOSYS; return -1; }
static inline pid_t fork(void)
@@ -158,6 +154,8 @@ struct passwd *getpwuid(uid_t uid);
int setitimer(int type, struct itimerval *in, struct itimerval *out);
int sigaction(int sig, struct sigaction *in, struct sigaction *out);
int link(const char *oldpath, const char *newpath);
+int symlink(const char *oldpath, const char *newpath);
+int readlink(const char *path, char *buf, size_t bufsiz);
/*
* replacements of existing functions
--
1.7.3.4.3927.g47aaf
This is a combination of 3 patches that have been lost in merges.
.
> * ln -s : doesn't make ntfs symlinks - had to replace it with a function
> that calls mklink.
> * test -h : doesn't work for ntfs symlinks - had to replace it with a
> function that uses dir /a+l
> (At least dir has the courtesy of failing if the file is not found with
> the correct attributes)
> * rm : doesn't work on a dangling (ntfs) symlink.
> * ls : doesn't work on a dangling (ntfs) smlink
>
There is work in progress to bring the ability to create and deal with
native symlinks on MSYS.
See patch #3046195 "Native symlinks" on the MinGW patch tracker:
http://sourceforge.net/tracker/index.php?func=detail&aid=3046195&group_id=2435&atid=302435
Regards,
Cesar
On Wed, 2 Feb 2011, Michael wrote:
> On Tuesday, January 25, 2011 2:12:33 PM UTC+8, Michael wrote:
> >
> > This is a combination of 3 patches that have been lost in merges.
Sorry, I might have missed it (and the last 2 weeks of hackathon craziness
did not help my memory), so please indulge with me: did you set up a fork
on github or repo.or.cz yet?
Ciao,
Dscho
http://github.com/frogonwheels/git
branch: unicode_symlink
I've merged with the latest /devel
//.