From 7e6be89c62d92cd8663e21e4fe7449bbaef4e44f Mon Sep 17 00:00:00 2001 From: Tor Lillqvist Date: Fri, 31 Dec 2004 01:15:15 +0000 Subject: [PATCH] Rewrite the Win32 version to use GetFileAttributes() instead of stat(). 2004-12-31 Tor Lillqvist * glib/gfileutils.c (g_file_test): Rewrite the Win32 version to use GetFileAttributes() instead of stat(). stat() is unreliable for corner cases like '\\server\share' or '.\'. Part of fixing #161797. When testing for executability, in addition to the fixed set of executable file name extensions also check the PATHEXT environment variable. --- ChangeLog | 15 +++- ChangeLog.pre-2-10 | 15 +++- ChangeLog.pre-2-12 | 15 +++- ChangeLog.pre-2-6 | 15 +++- ChangeLog.pre-2-8 | 15 +++- glib/gfileutils.c | 198 ++++++++++++++++++++++++++++++----------------------- 6 files changed, 174 insertions(+), 99 deletions(-) diff --git a/ChangeLog b/ChangeLog index 7e3b1bd..1803cd2 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,8 +1,17 @@ +2004-12-31 Tor Lillqvist + + * glib/gfileutils.c (g_file_test): Rewrite the Win32 version to + use GetFileAttributes() instead of stat(). stat() is unreliable + for corner cases like '\\server\share' or '.\'. Part of fixing + #161797. When testing for executability, in addition to the fixed + set of executable file name extensions also check the PATHEXT + environment variable. + 2004-12-30 Tor Lillqvist - * glib/gutils.c (g_get_current_dir): Use GetCurrentDirectory() - directly for simpler buffer length management. I don't trust - getcwd() getting it right all the time. + * glib/gutils.c (g_get_current_dir): In the Win32 version, use + GetCurrentDirectory() directly for simpler buffer length + management. I don't trust getcwd() getting it right all the time. 2004-12-30 Matthias Clasen diff --git a/ChangeLog.pre-2-10 b/ChangeLog.pre-2-10 index 7e3b1bd..1803cd2 100644 --- a/ChangeLog.pre-2-10 +++ b/ChangeLog.pre-2-10 @@ -1,8 +1,17 @@ +2004-12-31 Tor Lillqvist + + * glib/gfileutils.c (g_file_test): Rewrite the Win32 version to + use GetFileAttributes() instead of stat(). stat() is unreliable + for corner cases like '\\server\share' or '.\'. Part of fixing + #161797. When testing for executability, in addition to the fixed + set of executable file name extensions also check the PATHEXT + environment variable. + 2004-12-30 Tor Lillqvist - * glib/gutils.c (g_get_current_dir): Use GetCurrentDirectory() - directly for simpler buffer length management. I don't trust - getcwd() getting it right all the time. + * glib/gutils.c (g_get_current_dir): In the Win32 version, use + GetCurrentDirectory() directly for simpler buffer length + management. I don't trust getcwd() getting it right all the time. 2004-12-30 Matthias Clasen diff --git a/ChangeLog.pre-2-12 b/ChangeLog.pre-2-12 index 7e3b1bd..1803cd2 100644 --- a/ChangeLog.pre-2-12 +++ b/ChangeLog.pre-2-12 @@ -1,8 +1,17 @@ +2004-12-31 Tor Lillqvist + + * glib/gfileutils.c (g_file_test): Rewrite the Win32 version to + use GetFileAttributes() instead of stat(). stat() is unreliable + for corner cases like '\\server\share' or '.\'. Part of fixing + #161797. When testing for executability, in addition to the fixed + set of executable file name extensions also check the PATHEXT + environment variable. + 2004-12-30 Tor Lillqvist - * glib/gutils.c (g_get_current_dir): Use GetCurrentDirectory() - directly for simpler buffer length management. I don't trust - getcwd() getting it right all the time. + * glib/gutils.c (g_get_current_dir): In the Win32 version, use + GetCurrentDirectory() directly for simpler buffer length + management. I don't trust getcwd() getting it right all the time. 2004-12-30 Matthias Clasen diff --git a/ChangeLog.pre-2-6 b/ChangeLog.pre-2-6 index 7e3b1bd..1803cd2 100644 --- a/ChangeLog.pre-2-6 +++ b/ChangeLog.pre-2-6 @@ -1,8 +1,17 @@ +2004-12-31 Tor Lillqvist + + * glib/gfileutils.c (g_file_test): Rewrite the Win32 version to + use GetFileAttributes() instead of stat(). stat() is unreliable + for corner cases like '\\server\share' or '.\'. Part of fixing + #161797. When testing for executability, in addition to the fixed + set of executable file name extensions also check the PATHEXT + environment variable. + 2004-12-30 Tor Lillqvist - * glib/gutils.c (g_get_current_dir): Use GetCurrentDirectory() - directly for simpler buffer length management. I don't trust - getcwd() getting it right all the time. + * glib/gutils.c (g_get_current_dir): In the Win32 version, use + GetCurrentDirectory() directly for simpler buffer length + management. I don't trust getcwd() getting it right all the time. 2004-12-30 Matthias Clasen diff --git a/ChangeLog.pre-2-8 b/ChangeLog.pre-2-8 index 7e3b1bd..1803cd2 100644 --- a/ChangeLog.pre-2-8 +++ b/ChangeLog.pre-2-8 @@ -1,8 +1,17 @@ +2004-12-31 Tor Lillqvist + + * glib/gfileutils.c (g_file_test): Rewrite the Win32 version to + use GetFileAttributes() instead of stat(). stat() is unreliable + for corner cases like '\\server\share' or '.\'. Part of fixing + #161797. When testing for executability, in addition to the fixed + set of executable file name extensions also check the PATHEXT + environment variable. + 2004-12-30 Tor Lillqvist - * glib/gutils.c (g_get_current_dir): Use GetCurrentDirectory() - directly for simpler buffer length management. I don't trust - getcwd() getting it right all the time. + * glib/gutils.c (g_get_current_dir): In the Win32 version, use + GetCurrentDirectory() directly for simpler buffer length + management. I don't trust getcwd() getting it right all the time. 2004-12-30 Matthias Clasen diff --git a/glib/gfileutils.c b/glib/gfileutils.c index c3acb6c..a9a14c5 100644 --- a/glib/gfileutils.c +++ b/glib/gfileutils.c @@ -38,21 +38,7 @@ #include #ifdef G_OS_WIN32 -#include -#ifndef F_OK -#define F_OK 0 -#define W_OK 2 -#define R_OK 4 -#endif /* !F_OK */ - -#ifndef S_ISREG -#define S_ISREG(mode) ((mode)&_S_IFREG) -#endif - -#ifndef S_ISDIR -#define S_ISDIR(mode) ((mode)&_S_IFDIR) -#endif - +#include #endif /* G_OS_WIN32 */ #ifndef S_ISLNK @@ -68,7 +54,7 @@ /** * g_file_test: - * @filename: a filename to test + * @filename: a filename to test in the GLib file name encoding * @test: bitfield of #GFileTest flags * * Returns %TRUE if any of the tests in the bitfield @test are @@ -107,6 +93,12 @@ * the answer for the real user ID and group ID, rather than the * effective user ID and group ID. * + * On Windows, there are no symlinks, so testing for + * %G_FILE_TEST_IS_SYMLINK will always return %FALSE. Testing for + * %G_FILE_TEST_IS_EXECUTABLE will just check that the file exists and + * its name indicates that it is executable, checking for well-known + * extensions and those listed in the %PATHEXT environment variable. + * * Return value: whether a test was %TRUE **/ gboolean @@ -114,6 +106,8 @@ g_file_test (const gchar *filename, GFileTest test) { #ifdef G_OS_WIN32 + int attributes; + if (G_WIN32_HAVE_WIDECHAR_API ()) { wchar_t *wfilename = g_utf8_to_utf16 (filename, -1, NULL, NULL, NULL); @@ -121,91 +115,127 @@ g_file_test (const gchar *filename, if (wfilename == NULL) return FALSE; - if ((test & G_FILE_TEST_EXISTS) && (_waccess (wfilename, F_OK) == 0)) - { - g_free (wfilename); - return TRUE; - } - - if (test & (G_FILE_TEST_IS_REGULAR | - G_FILE_TEST_IS_DIR | - G_FILE_TEST_IS_EXECUTABLE)) - { - struct _stat s; - - if (_wstat (wfilename, &s) == 0) - { - if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG (s.st_mode)) - { - g_free (wfilename); - return TRUE; - } - - if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode)) - { - g_free (wfilename); - return TRUE; - } - - if ((test & G_FILE_TEST_IS_EXECUTABLE) && - (s.st_mode & _S_IEXEC)) - { - g_free (wfilename); - return TRUE; - } - } - } + attributes = GetFileAttributesW (wfilename); g_free (wfilename); - - return FALSE; } else { - gchar *cp_filename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL); + gchar *cpfilename = g_locale_from_utf8 (filename, -1, NULL, NULL, NULL); - if (cp_filename == NULL) + if (cpfilename == NULL) return FALSE; - if ((test & G_FILE_TEST_EXISTS) && (access (cp_filename, F_OK) == 0)) + attributes = GetFileAttributesA (cpfilename); + + g_free (cpfilename); + } + + if (attributes == INVALID_FILE_ATTRIBUTES) + return FALSE; + + if (test & G_FILE_TEST_EXISTS) + return TRUE; + + if (test & G_FILE_TEST_IS_REGULAR) + return (attributes & (FILE_ATTRIBUTE_DIRECTORY | FILE_ATTRIBUTE_DEVICE)) == 0; + + if (test & G_FILE_TEST_IS_DIR) + return (attributes & FILE_ATTRIBUTE_DIRECTORY) != 0; + + if (test & G_FILE_TEST_IS_EXECUTABLE) + { + const gchar *lastdot = strrchr (filename, '.'); + gchar *pathext = NULL, *tem, *p; + int extlen; + + if (lastdot == NULL) + return FALSE; + + if (stricmp (lastdot, ".exe") == 0 || + stricmp (lastdot, ".cmd") == 0 || + stricmp (lastdot, ".bat") == 0 || + stricmp (lastdot, ".com") == 0) + return TRUE; + + /* Check if it is one of the types listed in %PATHEXT% */ + + /* Perhaps unfortunately, g_getenv() doesn't return UTF-8, but + * system codepage. And _wgetenv() isn't useful either, as the C + * runtime just keeps system codepage versions of the + * environment variables in applications that aren't built + * specially. So use GetEnvironmentVariableW(). + */ + if (G_WIN32_HAVE_WIDECHAR_API ()) { - g_free (cp_filename); - return TRUE; + wchar_t dummy[2], *wvar; + int len; + + len = GetEnvironmentVariableW (L"PATHEXT", dummy, 2); + + if (len == 0) + return FALSE; + + wvar = g_new (wchar_t, len); + + if (GetEnvironmentVariableW (L"PATHEXT", wvar, len) == len - 1) + pathext = g_utf16_to_utf8 (wvar, -1, NULL, NULL, NULL); + + g_free (wvar); } - - if (test & (G_FILE_TEST_IS_REGULAR | - G_FILE_TEST_IS_DIR | - G_FILE_TEST_IS_EXECUTABLE)) + else { - struct stat s; - - if (stat (cp_filename, &s) == 0) + gchar dummy[2], *cpvar; + int len; + + len = GetEnvironmentVariableA ("PATHEXT", dummy, 2); + + if (len == 0) + return FALSE; + + cpvar = g_new (gchar, len); + + if (GetEnvironmentVariableA ("PATHEXT", cpvar, len) == len - 1) + pathext = g_locale_to_utf8 (cpvar, -1, NULL, NULL, NULL); + + g_free (cpvar); + } + + if (pathext == NULL) + return FALSE; + + tem = pathext; + pathext = g_utf8_casefold (pathext, -1); + g_free (tem); + + lastdot = g_utf8_casefold (lastdot, -1); + extlen = strlen (lastdot); + + p = pathext; + while (TRUE) + { + gchar *q = strchr (p, ';'); + if (q == NULL) + q = p + strlen (p); + if (extlen == q - p && + memcmp (lastdot, p, extlen) == 0) { - if ((test & G_FILE_TEST_IS_REGULAR) && S_ISREG (s.st_mode)) - { - g_free (cp_filename); - return TRUE; - } - - if ((test & G_FILE_TEST_IS_DIR) && S_ISDIR (s.st_mode)) - { - g_free (cp_filename); - return TRUE; - } - - if ((test & G_FILE_TEST_IS_EXECUTABLE) && - (s.st_mode & _S_IEXEC)) - { - g_free (cp_filename); - return TRUE; - } + g_free (pathext); + g_free ((gchar *) lastdot); + return TRUE; } + if (*q) + p = q + 1; + else + break; } - g_free (cp_filename); - + g_free (pathext); + g_free ((gchar *) lastdot); return FALSE; } + + return FALSE; #else if ((test & G_FILE_TEST_EXISTS) && (access (filename, F_OK) == 0)) return TRUE; -- 2.7.4