Pārlūkot izejas kodu

windows: (re)added support for symbolic links.

Ryan C. Gordon 8 gadi atpakaļ
vecāks
revīzija
84231feb0f
2 mainītis faili ar 41 papildinājumiem un 9 dzēšanām
  1. 0 2
      docs/TODO.txt
  2. 41 7
      src/platform_windows.c

+ 0 - 2
docs/TODO.txt

@@ -62,8 +62,6 @@ Other stuff I thought of...
 - Doxygen replacement? (manpages suck.)
 - Fix coding standards to match.
 - See if we can ditch some #include lines...
-- We lost Vista symlink support when removing isSymLink(). Pull it back from
-  revision control.
 - PHYSFS_exists() fails if you mountIo with a NULL filename. We need to decide
   how this API should work.
 - ZIP64 support?

+ 41 - 7
src/platform_windows.c

@@ -42,6 +42,7 @@
 #define PHYSFS_INVALID_FILE_ATTRIBUTES   0xFFFFFFFF
 
 /* Not defined before the Vista SDK. */
+#define PHYSFS_FILE_ATTRIBUTE_REPARSE_POINT 0x400
 #define PHYSFS_IO_REPARSE_TAG_SYMLINK    0xA000000C
 
 
@@ -866,17 +867,47 @@ static PHYSFS_sint64 FileTimeToPhysfsTime(const FILETIME *ft)
 } /* FileTimeToPhysfsTime */
 
 
+/* check for symlinks. These exist in NTFS 3.1 (WinXP), even though
+   they aren't really available to userspace before Vista. I wonder
+   what would happen if you put an NTFS disk with a symlink on it
+   into an XP machine, though; would this flag get set?
+   NTFS symlinks are a form of "reparse point" (junction, volume mount,
+   etc), so if the REPARSE_POINT attribute is set, check for the symlink
+   tag thereafter. This assumes you already read in the file attributes. */
+static int isSymlink(const WCHAR *wpath, const DWORD attr)
+{
+    WIN32_FIND_DATAW w32dw;
+    HANDLE h;
+
+    if ((attr & PHYSFS_FILE_ATTRIBUTE_REPARSE_POINT) == 0)
+        return 0;  /* not a reparse point? Definitely not a symlink. */
+
+    h = FindFirstFileW(wpath, &w32dw);
+    if (h == INVALID_HANDLE_VALUE)
+        return 0;  /* ...maybe the file just vanished...? */
+
+    FindClose(h);
+    return (w32dw.dwReserved == PHYSFS_IO_REPARSE_TAG_SYMLINK);
+} /* isSymlink */
+
+
 int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st)
 {
     WIN32_FILE_ATTRIBUTE_DATA winstat;
     WCHAR *wstr = NULL;
     DWORD err = 0;
     BOOL rc = 0;
+    int issymlink = 0;
 
     UTF8_TO_UNICODE_STACK(wstr, filename);
     BAIL_IF(!wstr, PHYSFS_ERR_OUT_OF_MEMORY, 0);
     rc = GetFileAttributesExW(wstr, GetFileExInfoStandard, &winstat);
-    err = (!rc) ? GetLastError() : 0;
+
+    if (!rc)
+        err = GetLastError();
+    else  /* check for symlink while wstr is still available */
+        issymlink = isSymlink(wstr, winstat.dwFileAttributes);
+
     __PHYSFS_smallFree(wstr);
     BAIL_IF(!rc, errcodeFromWinApiError(err), 0);
 
@@ -884,22 +915,25 @@ int __PHYSFS_platformStat(const char *filename, PHYSFS_Stat *st)
     st->accesstime = FileTimeToPhysfsTime(&winstat.ftLastAccessTime);
     st->createtime = FileTimeToPhysfsTime(&winstat.ftCreationTime);
 
-    if(winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+    if (issymlink)
     {
-        st->filetype = PHYSFS_FILETYPE_DIRECTORY;
+        st->filetype = PHYSFS_FILETYPE_SYMLINK;
         st->filesize = 0;
     } /* if */
 
-    else if(winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DEVICE))
+    else if (winstat.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
+    {
+        st->filetype = PHYSFS_FILETYPE_DIRECTORY;
+        st->filesize = 0;
+    } /* else if */
+
+    else if (winstat.dwFileAttributes & (FILE_ATTRIBUTE_OFFLINE | FILE_ATTRIBUTE_DEVICE))
     {
-        /* !!! FIXME: what are reparse points? */
         st->filetype = PHYSFS_FILETYPE_OTHER;
         /* !!! FIXME: don't rely on this */
         st->filesize = 0;
     } /* else if */
 
-    /* !!! FIXME: check for symlinks on Vista. */
-
     else
     {
         st->filetype = PHYSFS_FILETYPE_REGULAR;