diff -r 74686ae0b181 src/os_win32.c
--- a/src/os_win32.c	Fri Mar 16 20:16:46 2012 +0100
+++ b/src/os_win32.c	Wed Mar 21 02:19:56 2012 -0400
@@ -2568,57 +2568,70 @@
 /*
  * get file permissions for `name'
  * -1 : error
- * else FILE_ATTRIBUTE_* defined in winnt.h
+ * else mode_t
  */
     long
 mch_getperm(char_u *name)
 {
+    struct _stat st;
+    int n;
 #ifdef FEAT_MBYTE
     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
     {
 	WCHAR	*p = enc_to_utf16(name, NULL);
-	long	n;
 
 	if (p != NULL)
 	{
-	    n = (long)GetFileAttributesW(p);
+	    n = _wstat(p, &st);
 	    vim_free(p);
-	    if (n >= 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
-		return n;
+	    if (n == 0)
+		return st.st_mode;
+	    if (GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+		return -1;
 	    /* Retry with non-wide function (for Windows 98). */
 	}
     }
 #endif
-    return (long)GetFileAttributes((char *)name);
+    n = _stat(name, &st);
+    return n == 0 ? (int)st.st_mode : -1;
 }
 
 
 /*
  * set file permission for `name' to `perm'
+ *
+ * return FAIL for failure, OK otherwise
  */
     int
 mch_setperm(
     char_u  *name,
     long    perm)
 {
-    perm |= FILE_ATTRIBUTE_ARCHIVE;	/* file has changed, set archive bit */
+    long	n;
 #ifdef FEAT_MBYTE
+    WCHAR *p;
     if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
     {
-	WCHAR	*p = enc_to_utf16(name, NULL);
-	long	n;
+	p = enc_to_utf16(name, NULL);
 
 	if (p != NULL)
 	{
-	    n = (long)SetFileAttributesW(p, perm);
+	    n = _wchmod(p, perm);
 	    vim_free(p);
-	    if (n || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
-		return n ? OK : FAIL;
+	    if (n == -1 && GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
+		return FAIL;
 	    /* Retry with non-wide function (for Windows 98). */
 	}
     }
+    if (p == NULL)
 #endif
-    return SetFileAttributes((char *)name, perm) ? OK : FAIL;
+	n = _chmod(name, perm);
+    if (n == -1)
+	return FAIL;
+
+    win32_set_archive(name);
+
+    return OK;
 }
 
 /*
@@ -2627,49 +2640,12 @@
     void
 mch_hide(char_u *name)
 {
-    int		perm;
-#ifdef FEAT_MBYTE
-    WCHAR	*p = NULL;
-
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-	p = enc_to_utf16(name, NULL);
-#endif
-
-#ifdef FEAT_MBYTE
-    if (p != NULL)
-    {
-	perm = GetFileAttributesW(p);
-	if (perm < 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
-	{
-	    /* Retry with non-wide function (for Windows 98). */
-	    vim_free(p);
-	    p = NULL;
-	}
-    }
-    if (p == NULL)
-#endif
-	perm = GetFileAttributes((char *)name);
-    if (perm >= 0)
-    {
-	perm |= FILE_ATTRIBUTE_HIDDEN;
-#ifdef FEAT_MBYTE
-	if (p != NULL)
-	{
-	    if (SetFileAttributesW(p, perm) == 0
-		    && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
-	    {
-		/* Retry with non-wide function (for Windows 98). */
-		vim_free(p);
-		p = NULL;
-	    }
-	}
-	if (p == NULL)
-#endif
-	    SetFileAttributes((char *)name, perm);
-    }
-#ifdef FEAT_MBYTE
-    vim_free(p);
-#endif
+    int attrs = win32_getattrs(name);
+    if (attrs == -1)
+	return;
+
+    attrs |= FILE_ATTRIBUTE_HIDDEN;
+    win32_setattrs(name, attrs);
 }
 
 /*
@@ -2679,7 +2655,7 @@
     int
 mch_isdir(char_u *name)
 {
-    int f = mch_getperm(name);
+    int f = win32_getattrs(name);
 
     if (f == -1)
 	return FALSE;		    /* file does not exist at all */
@@ -2712,15 +2688,21 @@
 }
 
 /*
- * Return TRUE if file "fname" has more than one link.
+ * Return TRUE if file "fname" has more than one link or if it is a symbolic link.
  */
     int
 mch_is_linked(char_u *fname)
 {
     BY_HANDLE_FILE_INFORMATION info;
 
-    return win32_fileinfo(fname, &info) == FILEINFO_OK
-						   && info.nNumberOfLinks > 1;
+    if (win32_fileinfo(fname, &info) == FILEINFO_OK
+						   && info.nNumberOfLinks > 1)
+ 	return TRUE;
+
+    if (win32_file_is_symbolic_link(fname))
+ 	return TRUE;
+
+    return FALSE;
 }
 
 /*
@@ -2786,6 +2768,140 @@
     return res;
 }
 
+    int
+win32_getattrs(char_u *name)
+{
+    int		attr;
+#ifdef FEAT_MBYTE
+    WCHAR	*p = NULL;
+
+    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+	p = enc_to_utf16(name, NULL);
+
+    if (p != NULL)
+    {
+	attr = GetFileAttributesW(p);
+	if (attr < 0 && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+	{
+	    /* Retry with non-wide function (for Windows 98). */
+	    vim_free(p);
+	    p = NULL;
+	}
+    }
+    if (p == NULL)
+#endif
+	attr = GetFileAttributes((char *)name);
+#ifdef FEAT_MBYTE
+    vim_free(p);
+#endif
+    return attr;
+}
+
+    int
+win32_setattrs(char_u *name, int attrs)
+{
+    int res;
+#ifdef FEAT_MBYTE
+    WCHAR	*p = NULL;
+
+    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+	p = enc_to_utf16(name, NULL);
+
+    if (p != NULL)
+    {
+	res = SetFileAttributesW(p, attrs);
+	if (res == 0
+	    && GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+	{
+	    /* Retry with non-wide function (for Windows 98). */
+	    vim_free(p);
+	    p = NULL;
+	}
+	else
+	    res = -1;
+    }
+    if (p == NULL)
+#endif
+	SetFileAttributes((char *)name, attrs);
+#ifdef FEAT_MBYTE
+    vim_free(p);
+#endif
+    return res;
+}
+
+/*
+ * Set archive flag for "name".
+ */
+    int
+win32_set_archive(char_u *name)
+{
+    int attrs = win32_getattrs(name);
+    if (attrs == -1)
+	return -1;
+
+    attrs |= FILE_ATTRIBUTE_ARCHIVE;
+    return win32_setattrs(name, attrs);
+}
+
+    int
+win32_file_is_symbolic_link(char_u *fname)
+{
+    HANDLE hFind;
+    int res = FALSE;
+    WIN32_FIND_DATAA findDataA;
+    DWORD fileFlags = 0, reparseTag = 0;
+#ifdef FEAT_MBYTE
+    WCHAR	*wn = NULL;
+    WIN32_FIND_DATAW findDataW;
+
+    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
+    {
+	wn = enc_to_utf16(fname, NULL);
+    }
+    if (wn != NULL)
+    {
+	hFind = FindFirstFileW(wn, &findDataW);
+	if (hFind == INVALID_HANDLE_VALUE)
+	{
+	    vim_free(wn);
+
+	    if(GetLastError() == ERROR_CALL_NOT_IMPLEMENTED)
+	    {
+		/* Retry with non-wide function (for Windows 98). */
+
+		hFind = FindFirstFile(fname, &findDataA);
+		if (hFind != INVALID_HANDLE_VALUE)
+		{
+		    fileFlags = findDataA.dwFileAttributes;
+		    reparseTag = findDataA.dwReserved0;
+		}
+	    }
+	}
+	else
+	{
+	    fileFlags = findDataW.dwFileAttributes;
+	    reparseTag = findDataW.dwReserved0;
+	}
+    }
+#else
+    hFind = FindFirstFile(fname, &findDataA);
+    if (hFind != INVALID_HANDLE_VALUE)
+    {
+	fileFlags = findDataA.dwFileAttributes;
+	reparseTag = findDataA.dwReserved0;
+    }
+#endif
+
+    if (hFind != INVALID_HANDLE_VALUE)
+	FindClose(hFind);
+
+    if ( (fileFlags & 0x400) /* FILE_ATTRIBUTE_REPARSE_POINT */ == 0x400
+	    && reparseTag == 0xA000000C /* IO_REPARSE_TAG_SYMLINK */ )
+	res = TRUE;
+
+    return res;
+}
+
 /*
  * Return TRUE if file or directory "name" is writable (not readonly).
  * Strange semantics of Win32: a readonly directory is writable, but you can't
@@ -2794,10 +2910,10 @@
     int
 mch_writable(char_u *name)
 {
-    int perm = mch_getperm(name);
-
-    return (perm != -1 && (!(perm & FILE_ATTRIBUTE_READONLY)
-				       || (perm & FILE_ATTRIBUTE_DIRECTORY)));
+    int attrs = win32_getattrs(name);
+
+    return (attrs != -1 && (!(attrs & FILE_ATTRIBUTE_READONLY)
+			  || (attrs & FILE_ATTRIBUTE_DIRECTORY)));
 }
 
 /*
@@ -4952,25 +5068,8 @@
     int
 mch_remove(char_u *name)
 {
-#ifdef FEAT_MBYTE
-    WCHAR	*wn = NULL;
-    int		n;
-
-    if (enc_codepage >= 0 && (int)GetACP() != enc_codepage)
-    {
-	wn = enc_to_utf16(name, NULL);
-	if (wn != NULL)
-	{
-	    SetFileAttributesW(wn, FILE_ATTRIBUTE_NORMAL);
-	    n = DeleteFileW(wn) ? 0 : -1;
-	    vim_free(wn);
-	    if (n == 0 || GetLastError() != ERROR_CALL_NOT_IMPLEMENTED)
-		return n;
-	    /* Retry with non-wide function (for Windows 98). */
-	}
-    }
-#endif
-    SetFileAttributes(name, FILE_ATTRIBUTE_NORMAL);
+    win32_setattrs(name, FILE_ATTRIBUTE_NORMAL);
+
     return DeleteFile(name) ? 0 : -1;
 }
 
diff -r 74686ae0b181 src/proto/os_win32.pro
--- a/src/proto/os_win32.pro	Fri Mar 16 20:16:46 2012 +0100
+++ b/src/proto/os_win32.pro	Wed Mar 21 02:19:56 2012 -0400
@@ -23,6 +23,10 @@
 int mch_mkdir __ARGS((char_u *name));
 int mch_is_linked __ARGS((char_u *fname));
 int win32_fileinfo __ARGS((char_u *name, BY_HANDLE_FILE_INFORMATION *lpFileInfo));
+int win32_getattrs __ARGS((char_u *name));
+int win32_setattrs __ARGS((char_u *name, int attrs));
+int win32_set_archive __ARGS((char_u *name));
+int win32_file_is_symbolic_link __ARGS((char_u *name));
 int mch_writable __ARGS((char_u *name));
 int mch_can_exe __ARGS((char_u *name));
 int mch_nodetype __ARGS((char_u *name));
