Skip to content

Commit

Permalink
windows: (re)added support for symbolic links.
Browse files Browse the repository at this point in the history
  • Loading branch information
icculus committed Jul 9, 2017
1 parent 3e5f92d commit 84231fe
Show file tree
Hide file tree
Showing 2 changed files with 41 additions and 9 deletions.
2 changes: 0 additions & 2 deletions docs/TODO.txt
Expand Up @@ -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?
Expand Down
48 changes: 41 additions & 7 deletions src/platform_windows.c
Expand Up @@ -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


Expand Down Expand Up @@ -866,40 +867,73 @@ 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);

st->modtime = FileTimeToPhysfsTime(&winstat.ftLastWriteTime);
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;
Expand Down

0 comments on commit 84231fe

Please sign in to comment.