mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2024-11-10 03:16:17 +01:00
Merge branch 'w32-gfileinfo-improvements' into 'master'
W32 GFileInfo improvements See merge request GNOME/glib!238
This commit is contained in:
commit
cf4ea5ef75
@ -85,6 +85,8 @@
|
||||
#define G_FILE_ATTRIBUTE_ID_UNIX_IS_MOUNTPOINT (7340032 + 10)
|
||||
#define G_FILE_ATTRIBUTE_ID_DOS_IS_ARCHIVE (8388608 + 1)
|
||||
#define G_FILE_ATTRIBUTE_ID_DOS_IS_SYSTEM (8388608 + 2)
|
||||
#define G_FILE_ATTRIBUTE_ID_DOS_IS_MOUNTPOINT (8388608 + 3)
|
||||
#define G_FILE_ATTRIBUTE_ID_DOS_REPARSE_POINT_TAG (8388608 + 4)
|
||||
#define G_FILE_ATTRIBUTE_ID_OWNER_USER (9437184 + 1)
|
||||
#define G_FILE_ATTRIBUTE_ID_OWNER_USER_REAL (9437184 + 2)
|
||||
#define G_FILE_ATTRIBUTE_ID_OWNER_GROUP (9437184 + 3)
|
||||
|
@ -245,6 +245,8 @@ ensure_attribute_hash (void)
|
||||
REGISTER_ATTRIBUTE (UNIX_IS_MOUNTPOINT);
|
||||
REGISTER_ATTRIBUTE (DOS_IS_ARCHIVE);
|
||||
REGISTER_ATTRIBUTE (DOS_IS_SYSTEM);
|
||||
REGISTER_ATTRIBUTE (DOS_IS_MOUNTPOINT);
|
||||
REGISTER_ATTRIBUTE (DOS_REPARSE_POINT_TAG);
|
||||
REGISTER_ATTRIBUTE (OWNER_USER);
|
||||
REGISTER_ATTRIBUTE (OWNER_USER_REAL);
|
||||
REGISTER_ATTRIBUTE (OWNER_GROUP);
|
||||
|
@ -672,6 +672,33 @@ typedef struct _GFileInfoClass GFileInfoClass;
|
||||
**/
|
||||
#define G_FILE_ATTRIBUTE_DOS_IS_SYSTEM "dos::is-system" /* boolean */
|
||||
|
||||
/**
|
||||
* G_FILE_ATTRIBUTE_DOS_IS_MOUNTPOINT:
|
||||
*
|
||||
* A key in the "dos" namespace for checking if the file is a NTFS mount point
|
||||
* (a volume mount or a junction point).
|
||||
* This attribute is %TRUE if file is a reparse point of type
|
||||
* [IO_REPARSE_TAG_MOUNT_POINT](https://msdn.microsoft.com/en-us/library/dd541667.aspx).
|
||||
* This attribute is only available for DOS file systems.
|
||||
* Corresponding #GFileAttributeType is %G_FILE_ATTRIBUTE_TYPE_BOOLEAN.
|
||||
*
|
||||
* Since: 2.60
|
||||
**/
|
||||
#define G_FILE_ATTRIBUTE_DOS_IS_MOUNTPOINT "dos::is-mountpoint" /* boolean */
|
||||
|
||||
/**
|
||||
* G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG:
|
||||
*
|
||||
* A key in the "dos" namespace for getting the file NTFS reparse tag.
|
||||
* This value is 0 for files that are not reparse points.
|
||||
* See the [Reparse Tags](https://msdn.microsoft.com/en-us/library/dd541667.aspx)
|
||||
* page for possible reparse tag values. Corresponding #GFileAttributeType
|
||||
* is %G_FILE_ATTRIBUTE_TYPE_UINT32.
|
||||
*
|
||||
* Since: 2.60
|
||||
**/
|
||||
#define G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG "dos::reparse-point-tag" /* uint32 */
|
||||
|
||||
/* Owner attributes */
|
||||
|
||||
/**
|
||||
|
@ -1867,6 +1867,12 @@ _g_local_file_info_get (const char *basename,
|
||||
|
||||
if (statbuf.attributes & FILE_ATTRIBUTE_SYSTEM)
|
||||
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_SYSTEM, TRUE);
|
||||
|
||||
if (statbuf.reparse_tag == IO_REPARSE_TAG_MOUNT_POINT)
|
||||
_g_file_info_set_attribute_boolean_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_IS_MOUNTPOINT, TRUE);
|
||||
|
||||
if (statbuf.reparse_tag != 0)
|
||||
_g_file_info_set_attribute_uint32_by_id (info, G_FILE_ATTRIBUTE_ID_DOS_REPARSE_POINT_TAG, statbuf.reparse_tag);
|
||||
#endif
|
||||
|
||||
symlink_target = NULL;
|
||||
|
@ -180,16 +180,24 @@ test_internal_enhanced_stdio (void)
|
||||
gchar *programdata;
|
||||
gchar *users_dir;
|
||||
gchar *allusers;
|
||||
GFile *gf_programdata, *gf_allusers;
|
||||
GFileInfo *fi_programdata, *fi_allusers, *fi_allusers_target;
|
||||
gchar *commondata;
|
||||
GFile *gf_programdata, *gf_allusers, *gf_commondata;
|
||||
GFileInfo *fi_programdata, *fi_allusers, *fi_allusers_target, *fi_commondata, *fi_commondata_target;
|
||||
GFileType ft_allusers;
|
||||
GFileType ft_allusers_target;
|
||||
GFileType ft_programdata;
|
||||
GFileType ft_commondata;
|
||||
gboolean allusers_is_symlink;
|
||||
gboolean commondata_is_symlink;
|
||||
gboolean commondata_is_mount_point;
|
||||
guint32 allusers_reparse_tag;
|
||||
guint32 commondata_reparse_tag;
|
||||
const gchar *id_allusers;
|
||||
const gchar *id_allusers_target;
|
||||
const gchar *id_commondata_target;
|
||||
const gchar *id_programdata;
|
||||
const gchar *allusers_target;
|
||||
const gchar *commondata_target;
|
||||
|
||||
/* C:/ProgramData */
|
||||
programdata = g_utf16_to_utf8 (programdata_dir_w, -1, NULL, NULL, NULL);
|
||||
@ -201,7 +209,11 @@ test_internal_enhanced_stdio (void)
|
||||
* for "C:/ProgramData".
|
||||
*/
|
||||
allusers = g_build_filename (users_dir, "All Users", NULL);
|
||||
g_assert_nonnull (allusers);
|
||||
|
||||
/* "C:/Users/All Users/Application Data" is a known
|
||||
* junction for "C:/ProgramData"
|
||||
*/
|
||||
commondata = g_build_filename (allusers, "Application Data", NULL);
|
||||
|
||||
/* We don't test g_stat() and g_lstat() on these directories,
|
||||
* because it is pointless - there's no way to tell that these
|
||||
@ -213,6 +225,7 @@ test_internal_enhanced_stdio (void)
|
||||
*/
|
||||
gf_programdata = g_file_new_for_path (programdata);
|
||||
gf_allusers = g_file_new_for_path (allusers);
|
||||
gf_commondata = g_file_new_for_path (commondata);
|
||||
|
||||
fi_programdata = g_file_query_info (gf_programdata,
|
||||
G_FILE_ATTRIBUTE_ID_FILE ","
|
||||
@ -229,52 +242,99 @@ test_internal_enhanced_stdio (void)
|
||||
fi_allusers = g_file_query_info (gf_allusers,
|
||||
G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET ","
|
||||
G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
|
||||
G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG ","
|
||||
G_FILE_ATTRIBUTE_ID_FILE ","
|
||||
G_FILE_ATTRIBUTE_STANDARD_TYPE,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
NULL, NULL);
|
||||
|
||||
g_assert (g_file_info_has_attribute (fi_programdata, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert (g_file_info_has_attribute (fi_programdata, G_FILE_ATTRIBUTE_STANDARD_TYPE));
|
||||
fi_commondata = g_file_query_info (gf_commondata,
|
||||
G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET ","
|
||||
G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK ","
|
||||
G_FILE_ATTRIBUTE_DOS_IS_MOUNTPOINT ","
|
||||
G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG ","
|
||||
G_FILE_ATTRIBUTE_ID_FILE ","
|
||||
G_FILE_ATTRIBUTE_STANDARD_TYPE,
|
||||
G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS,
|
||||
NULL, NULL);
|
||||
|
||||
g_assert (g_file_info_has_attribute (fi_allusers_target, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert (g_file_info_has_attribute (fi_allusers_target, G_FILE_ATTRIBUTE_STANDARD_TYPE));
|
||||
fi_commondata_target = g_file_query_info (gf_commondata,
|
||||
G_FILE_ATTRIBUTE_ID_FILE ","
|
||||
G_FILE_ATTRIBUTE_STANDARD_TYPE,
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
NULL, NULL);
|
||||
|
||||
g_assert (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_TYPE));
|
||||
g_assert (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK));
|
||||
g_assert (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET));
|
||||
g_assert_true (g_file_info_has_attribute (fi_programdata, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_programdata, G_FILE_ATTRIBUTE_STANDARD_TYPE));
|
||||
|
||||
g_assert_true (g_file_info_has_attribute (fi_allusers_target, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_allusers_target, G_FILE_ATTRIBUTE_STANDARD_TYPE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_commondata_target, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_commondata_target, G_FILE_ATTRIBUTE_STANDARD_TYPE));
|
||||
|
||||
g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_TYPE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK));
|
||||
g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG));
|
||||
g_assert_true (g_file_info_has_attribute (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET));
|
||||
|
||||
g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_STANDARD_TYPE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK));
|
||||
g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_DOS_IS_MOUNTPOINT));
|
||||
g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG));
|
||||
g_assert_true (g_file_info_has_attribute (fi_commondata, G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET));
|
||||
|
||||
ft_allusers = g_file_info_get_file_type (fi_allusers);
|
||||
ft_allusers_target = g_file_info_get_file_type (fi_allusers_target);
|
||||
ft_programdata = g_file_info_get_file_type (fi_programdata);
|
||||
ft_commondata = g_file_info_get_file_type (fi_commondata);
|
||||
|
||||
g_assert (ft_allusers == G_FILE_TYPE_SYMBOLIC_LINK);
|
||||
g_assert (ft_allusers_target == G_FILE_TYPE_DIRECTORY);
|
||||
g_assert (ft_programdata == G_FILE_TYPE_DIRECTORY);
|
||||
g_assert_cmpint (ft_allusers, ==, G_FILE_TYPE_SYMBOLIC_LINK);
|
||||
g_assert_cmpint (ft_allusers_target, ==, G_FILE_TYPE_DIRECTORY);
|
||||
g_assert_cmpint (ft_programdata, ==, G_FILE_TYPE_DIRECTORY);
|
||||
g_assert_cmpint (ft_commondata, ==, G_FILE_TYPE_SYMBOLIC_LINK);
|
||||
|
||||
allusers_is_symlink = g_file_info_get_attribute_boolean (fi_allusers, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
|
||||
allusers_reparse_tag = g_file_info_get_attribute_uint32 (fi_allusers, G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG);
|
||||
commondata_is_symlink = g_file_info_get_attribute_boolean (fi_commondata, G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK);
|
||||
commondata_is_mount_point = g_file_info_get_attribute_boolean (fi_commondata, G_FILE_ATTRIBUTE_DOS_IS_MOUNTPOINT);
|
||||
commondata_reparse_tag = g_file_info_get_attribute_uint32 (fi_commondata, G_FILE_ATTRIBUTE_DOS_REPARSE_POINT_TAG);
|
||||
|
||||
g_assert_true (allusers_is_symlink);
|
||||
g_assert_cmpuint (allusers_reparse_tag, ==, IO_REPARSE_TAG_SYMLINK);
|
||||
g_assert_true (commondata_is_symlink);
|
||||
g_assert_true (commondata_is_mount_point);
|
||||
g_assert_cmpuint (commondata_reparse_tag, ==, IO_REPARSE_TAG_MOUNT_POINT);
|
||||
|
||||
id_allusers = g_file_info_get_attribute_string (fi_allusers, G_FILE_ATTRIBUTE_ID_FILE);
|
||||
id_allusers_target = g_file_info_get_attribute_string (fi_allusers_target, G_FILE_ATTRIBUTE_ID_FILE);
|
||||
id_commondata_target = g_file_info_get_attribute_string (fi_commondata_target, G_FILE_ATTRIBUTE_ID_FILE);
|
||||
id_programdata = g_file_info_get_attribute_string (fi_programdata, G_FILE_ATTRIBUTE_ID_FILE);
|
||||
|
||||
g_assert_cmpstr (id_allusers_target, ==, id_programdata);
|
||||
g_assert_cmpstr (id_commondata_target, ==, id_programdata);
|
||||
g_assert_cmpstr (id_allusers, !=, id_programdata);
|
||||
|
||||
allusers_target = g_file_info_get_symlink_target (fi_allusers);
|
||||
|
||||
g_assert_true (g_str_has_suffix (allusers_target, "ProgramData"));
|
||||
|
||||
commondata_target = g_file_info_get_symlink_target (fi_commondata);
|
||||
|
||||
g_assert_true (g_str_has_suffix (commondata_target, "ProgramData"));
|
||||
|
||||
g_object_unref (fi_allusers);
|
||||
g_object_unref (fi_allusers_target);
|
||||
g_object_unref (fi_commondata);
|
||||
g_object_unref (fi_commondata_target);
|
||||
g_object_unref (fi_programdata);
|
||||
g_object_unref (gf_allusers);
|
||||
g_object_unref (gf_commondata);
|
||||
g_object_unref (gf_programdata);
|
||||
|
||||
g_free (allusers);
|
||||
g_free (commondata);
|
||||
g_free (users_dir);
|
||||
g_free (programdata);
|
||||
}
|
||||
@ -325,7 +385,7 @@ test_internal_enhanced_stdio (void)
|
||||
g_assert_nonnull (f);
|
||||
|
||||
h = (HANDLE) _get_osfhandle (fileno (f));
|
||||
g_assert (h != INVALID_HANDLE_VALUE);
|
||||
g_assert_cmpuint ((guintptr) h, !=, (guintptr) INVALID_HANDLE_VALUE);
|
||||
|
||||
ssb.SetSparse = TRUE;
|
||||
g_assert_true (DeviceIoControl (h,
|
||||
@ -364,8 +424,8 @@ test_internal_enhanced_stdio (void)
|
||||
|
||||
g_remove (ps);
|
||||
|
||||
g_assert (g_file_info_has_attribute (fi_ps, G_FILE_ATTRIBUTE_STANDARD_SIZE));
|
||||
g_assert (g_file_info_has_attribute (fi_ps, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_ps, G_FILE_ATTRIBUTE_STANDARD_SIZE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_ps, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
|
||||
|
||||
size_ps = g_file_info_get_attribute_uint64 (fi_ps, G_FILE_ATTRIBUTE_STANDARD_SIZE);
|
||||
alsize_ps = g_file_info_get_attribute_uint64 (fi_ps, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE);
|
||||
@ -404,7 +464,7 @@ test_internal_enhanced_stdio (void)
|
||||
g_assert_nonnull (f);
|
||||
|
||||
h = (HANDLE) _get_osfhandle (fileno (f));
|
||||
g_assert (h != INVALID_HANDLE_VALUE);
|
||||
g_assert_cmpuint ((guintptr) h, !=, (guintptr) INVALID_HANDLE_VALUE);
|
||||
|
||||
fprintf (f, "1");
|
||||
fflush (f);
|
||||
@ -443,15 +503,15 @@ test_internal_enhanced_stdio (void)
|
||||
G_FILE_QUERY_INFO_NONE,
|
||||
NULL, NULL);
|
||||
|
||||
g_assert (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_STANDARD_SIZE));
|
||||
g_assert (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
|
||||
g_assert (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED));
|
||||
g_assert_true (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_STANDARD_SIZE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED));
|
||||
|
||||
g_assert (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_STANDARD_SIZE));
|
||||
g_assert (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
|
||||
g_assert (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_TIME_MODIFIED));
|
||||
g_assert_true (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_STANDARD_SIZE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_ID_FILE));
|
||||
g_assert_true (g_file_info_has_attribute (fi_p1, G_FILE_ATTRIBUTE_TIME_MODIFIED));
|
||||
|
||||
size_p0 = g_file_info_get_attribute_uint64 (fi_p0, G_FILE_ATTRIBUTE_STANDARD_SIZE);
|
||||
alsize_p0 = g_file_info_get_attribute_uint64 (fi_p0, G_FILE_ATTRIBUTE_STANDARD_ALLOCATED_SIZE);
|
||||
@ -469,7 +529,7 @@ test_internal_enhanced_stdio (void)
|
||||
/* st_ino from W32 stat() is useless for file identification.
|
||||
* It will be either 0, or it will be the same for both files.
|
||||
*/
|
||||
g_assert (statbuf_p0.st_ino == statbuf_p1.st_ino);
|
||||
g_assert_cmpint (statbuf_p0.st_ino, ==, statbuf_p1.st_ino);
|
||||
g_assert_cmpstr (id_p0, !=, id_p1);
|
||||
|
||||
time_p0 = g_file_info_get_attribute_uint64 (fi_p0, G_FILE_ATTRIBUTE_TIME_MODIFIED);
|
||||
@ -481,7 +541,7 @@ test_internal_enhanced_stdio (void)
|
||||
* and 64-bit on 64-bit Windows, usually),
|
||||
* so it *can* pass this test in some cases.
|
||||
*/
|
||||
g_assert (time_p0 > G_GUINT64_CONSTANT (0xFFFFFFFF));
|
||||
g_assert_cmpuint (time_p0, >, G_GUINT64_CONSTANT (0xFFFFFFFF));
|
||||
|
||||
g_object_unref (fi_p0);
|
||||
g_object_unref (fi_p1);
|
||||
|
77
glib/gstdio-private.c
Normal file
77
glib/gstdio-private.c
Normal file
@ -0,0 +1,77 @@
|
||||
/* gstdio-private.c - private glib functions for gstdio.c
|
||||
*
|
||||
* Copyright 2004 Tor Lillqvist
|
||||
* Copyright 2018 Руслан Ижбулатов
|
||||
*
|
||||
* This library is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU Lesser General Public
|
||||
* License as published by the Free Software Foundation; either
|
||||
* version 2.1 of the License, or (at your option) any later version.
|
||||
*
|
||||
* This library is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
||||
* Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received a copy of the GNU Lesser General Public License
|
||||
* along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/* Strips "\\\\?\\" extended prefix or
|
||||
* "\\??\\" NT Object Manager prefix from
|
||||
* @str in-place, using memmove.
|
||||
* @str_size must point to the size of @str
|
||||
* in gunichar2s, including NUL-terminator
|
||||
* (if @str is NUL-terminated; it doesn't have to be).
|
||||
* On return @str_size will correctly reflect changes
|
||||
* in @str size (if any).
|
||||
* Returns TRUE if @str was modified.
|
||||
*/
|
||||
static gboolean
|
||||
_g_win32_strip_extended_ntobjm_prefix (gunichar2 *str,
|
||||
gsize *str_size)
|
||||
{
|
||||
const wchar_t *extended_prefix = L"\\\\?\\";
|
||||
const gsize extended_prefix_len = wcslen (extended_prefix);
|
||||
const gsize extended_prefix_len_bytes = sizeof (gunichar2) * extended_prefix_len;
|
||||
const gsize extended_prefix_with_drive_len_bytes = sizeof (gunichar2) * (extended_prefix_len + 2);
|
||||
const wchar_t *ntobjm_prefix = L"\\??\\";
|
||||
const gsize ntobjm_prefix_len = wcslen (ntobjm_prefix);
|
||||
const gsize ntobjm_prefix_len_bytes = sizeof (gunichar2) * ntobjm_prefix_len;
|
||||
const gsize ntobjm_prefix_with_drive_len_bytes = sizeof (gunichar2) * (ntobjm_prefix_len + 2);
|
||||
gboolean do_move = FALSE;
|
||||
gsize move_shift = 0;
|
||||
|
||||
if ((*str_size) * sizeof (gunichar2) > extended_prefix_with_drive_len_bytes &&
|
||||
memcmp (str,
|
||||
extended_prefix,
|
||||
extended_prefix_len_bytes) == 0 &&
|
||||
iswascii (str[extended_prefix_len]) &&
|
||||
iswalpha (str[extended_prefix_len]) &&
|
||||
str[extended_prefix_len + 1] == L':')
|
||||
{
|
||||
do_move = TRUE;
|
||||
move_shift = extended_prefix_len;
|
||||
}
|
||||
else if ((*str_size) * sizeof (gunichar2) > ntobjm_prefix_with_drive_len_bytes &&
|
||||
memcmp (str,
|
||||
ntobjm_prefix,
|
||||
ntobjm_prefix_len_bytes) == 0 &&
|
||||
iswascii (str[ntobjm_prefix_len]) &&
|
||||
iswalpha (str[ntobjm_prefix_len]) &&
|
||||
str[ntobjm_prefix_len + 1] == L':')
|
||||
{
|
||||
do_move = TRUE;
|
||||
move_shift = ntobjm_prefix_len;
|
||||
}
|
||||
|
||||
if (do_move)
|
||||
{
|
||||
*str_size -= move_shift;
|
||||
memmove (str,
|
||||
str + move_shift,
|
||||
(*str_size) * sizeof (gunichar2));
|
||||
}
|
||||
|
||||
return do_move;
|
||||
}
|
@ -121,6 +121,8 @@ w32_error_to_errno (DWORD error_code)
|
||||
}
|
||||
}
|
||||
|
||||
#include "gstdio-private.c"
|
||||
|
||||
static int
|
||||
_g_win32_stat_utf16_no_trailing_slashes (const gunichar2 *filename,
|
||||
int fd,
|
||||
@ -259,15 +261,11 @@ _g_win32_stat_utf16_no_trailing_slashes (const gunichar2 *filename,
|
||||
|
||||
if (new_len > 0)
|
||||
{
|
||||
const wchar_t *extended_prefix = L"\\\\?\\";
|
||||
const gsize extended_prefix_len = wcslen (extended_prefix);
|
||||
const gsize extended_prefix_len_bytes = sizeof (wchar_t) * extended_prefix_len;
|
||||
|
||||
/* Pretend that new_len doesn't count the terminating NUL char,
|
||||
* and ask for a bit more space than is needed.
|
||||
* and ask for a bit more space than is needed, and allocate even more.
|
||||
*/
|
||||
filename_target_len = new_len + 5;
|
||||
filename_target = g_malloc (filename_target_len * sizeof (wchar_t));
|
||||
filename_target_len = new_len + 3;
|
||||
filename_target = g_malloc ((filename_target_len + 1) * sizeof (wchar_t));
|
||||
|
||||
new_len = GetFinalPathNameByHandleW (file_handle,
|
||||
filename_target,
|
||||
@ -284,17 +282,32 @@ _g_win32_stat_utf16_no_trailing_slashes (const gunichar2 *filename,
|
||||
error_code = ERROR_BUFFER_OVERFLOW;
|
||||
g_clear_pointer (&filename_target, g_free);
|
||||
}
|
||||
/* GetFinalPathNameByHandle() is documented to return extended paths,
|
||||
* strip the extended prefix.
|
||||
*/
|
||||
else if (new_len > extended_prefix_len &&
|
||||
memcmp (filename_target, extended_prefix, extended_prefix_len_bytes) == 0)
|
||||
else if (new_len == 0)
|
||||
{
|
||||
new_len -= extended_prefix_len;
|
||||
memmove (filename_target,
|
||||
filename_target + extended_prefix_len,
|
||||
(new_len + 1) * sizeof (wchar_t));
|
||||
g_clear_pointer (&filename_target, g_free);
|
||||
}
|
||||
/* GetFinalPathNameByHandle() is documented to return extended paths,
|
||||
* strip the extended prefix, if it is followed by a drive letter
|
||||
* and a colon. Otherwise keep it (the path could be
|
||||
* \\\\?\\Volume{GUID}\\ - it's only usable in extended form).
|
||||
*/
|
||||
else if (new_len > 0)
|
||||
{
|
||||
gsize len = new_len;
|
||||
|
||||
/* Account for NUL-terminator maybe not being counted.
|
||||
* This is why we overallocated earlier.
|
||||
*/
|
||||
if (filename_target[len] != L'\0')
|
||||
{
|
||||
len++;
|
||||
filename_target[len] = L'\0';
|
||||
}
|
||||
|
||||
_g_win32_strip_extended_ntobjm_prefix (filename_target, &len);
|
||||
new_len = len;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (new_len == 0)
|
||||
@ -453,8 +466,9 @@ _g_win32_readlink_utf16_raw (const gunichar2 *filename,
|
||||
* point and use DeviceIoControl() on it.
|
||||
*/
|
||||
h = CreateFileW (filename,
|
||||
FILE_READ_ATTRIBUTES | SYNCHRONIZE | GENERIC_READ,
|
||||
FILE_SHARE_READ, NULL, OPEN_EXISTING,
|
||||
FILE_READ_EA,
|
||||
FILE_SHARE_READ|FILE_SHARE_WRITE|FILE_SHARE_DELETE,
|
||||
NULL, OPEN_EXISTING,
|
||||
FILE_ATTRIBUTE_NORMAL
|
||||
| FILE_FLAG_OPEN_REPARSE_POINT
|
||||
| (attributes & FILE_ATTRIBUTE_DIRECTORY ? FILE_FLAG_BACKUP_SEMANTICS : 0),
|
||||
@ -513,10 +527,8 @@ _g_win32_readlink_utf16 (const gunichar2 *filename,
|
||||
gunichar2 *buf,
|
||||
gsize buf_size)
|
||||
{
|
||||
const wchar_t *ntobjm_prefix = L"\\??\\";
|
||||
const gsize ntobjm_prefix_len_unichar2 = wcslen (ntobjm_prefix);
|
||||
const gsize ntobjm_prefix_len_bytes = sizeof (gunichar2) * ntobjm_prefix_len_unichar2;
|
||||
int result = _g_win32_readlink_utf16_raw (filename, buf, buf_size);
|
||||
int result = _g_win32_readlink_utf16_raw (filename, buf, buf_size);
|
||||
gsize string_size;
|
||||
|
||||
if (result <= 0)
|
||||
return result;
|
||||
@ -532,16 +544,16 @@ _g_win32_readlink_utf16 (const gunichar2 *filename,
|
||||
/* DeviceIoControl () tends to return filenames as NT Object Manager
|
||||
* names , i.e. "\\??\\C:\\foo\\bar".
|
||||
* Remove the leading 4-byte \??\ prefix, as glib (as well as many W32 API
|
||||
* functions) is unprepared to deal with it.
|
||||
* functions) is unprepared to deal with it. Unless it has no 'x:' drive
|
||||
* letter part after the prefix, in which case we leave everything
|
||||
* as-is, because the path could be "\??\Volume{GUID}" - stripping
|
||||
* the prefix will allow it to be confused with relative links
|
||||
* targeting "Volume{GUID}".
|
||||
*/
|
||||
if (result > ntobjm_prefix_len_bytes &&
|
||||
memcmp (buf, ntobjm_prefix, ntobjm_prefix_len_bytes) == 0)
|
||||
{
|
||||
result -= ntobjm_prefix_len_bytes;
|
||||
memmove (buf, buf + ntobjm_prefix_len_unichar2, result);
|
||||
}
|
||||
string_size = result / sizeof (gunichar2);
|
||||
_g_win32_strip_extended_ntobjm_prefix (buf, &string_size);
|
||||
|
||||
return result;
|
||||
return string_size * sizeof (gunichar2);
|
||||
}
|
||||
|
||||
static gchar *
|
||||
|
@ -1009,6 +1009,139 @@ test_fopen_modes (void)
|
||||
g_free (path);
|
||||
}
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
#include "../gstdio-private.c"
|
||||
|
||||
static int
|
||||
g_wcscmp0 (const gunichar2 *str1,
|
||||
const gunichar2 *str2)
|
||||
{
|
||||
if (!str1)
|
||||
return -(str1 != str2);
|
||||
if (!str2)
|
||||
return str1 != str2;
|
||||
return wcscmp (str1, str2);
|
||||
}
|
||||
|
||||
#define g_assert_cmpwcs(s1, cmp, s2, s1u8, s2u8) \
|
||||
G_STMT_START { \
|
||||
const gunichar2 *__s1 = (s1), *__s2 = (s2); \
|
||||
if (g_wcscmp0 (__s1, __s2) cmp 0) ; else \
|
||||
g_assertion_message_cmpstr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, \
|
||||
#s1u8 " " #cmp " " #s2u8, s1u8, #cmp, s2u8); \
|
||||
} G_STMT_END
|
||||
|
||||
static void
|
||||
test_win32_pathstrip (void)
|
||||
{
|
||||
gunichar2 *buf;
|
||||
gsize i;
|
||||
#define IDENTITY_TEST(x) { x, x, FALSE }
|
||||
struct
|
||||
{
|
||||
gunichar2 *in;
|
||||
gunichar2 *out;
|
||||
gboolean result;
|
||||
} testcases[] = {
|
||||
IDENTITY_TEST (L"\\\\?\\V"),
|
||||
IDENTITY_TEST (L"\\\\?\\Vo"),
|
||||
IDENTITY_TEST (L"\\\\?\\Volume{0700f3d3-6d24-11e3-8b2f-806e6f6e6963}\\"),
|
||||
IDENTITY_TEST (L"\\??\\V"),
|
||||
IDENTITY_TEST (L"\\??\\Vo"),
|
||||
IDENTITY_TEST (L"\\??\\Volume{0700f3d3-6d24-11e3-8b2f-806e6f6e6963}\\"),
|
||||
IDENTITY_TEST (L"\\\\?\\\x0441:\\"),
|
||||
IDENTITY_TEST (L"\\??\\\x0441:\\"),
|
||||
IDENTITY_TEST (L"a:\\"),
|
||||
IDENTITY_TEST (L"a:\\b\\c"),
|
||||
IDENTITY_TEST (L"x"),
|
||||
#undef IDENTITY_TEST
|
||||
{
|
||||
L"\\\\?\\c:\\",
|
||||
L"c:\\",
|
||||
TRUE,
|
||||
},
|
||||
{
|
||||
L"\\\\?\\C:\\",
|
||||
L"C:\\",
|
||||
TRUE,
|
||||
},
|
||||
{
|
||||
L"\\\\?\\c:\\",
|
||||
L"c:\\",
|
||||
TRUE,
|
||||
},
|
||||
{
|
||||
L"\\\\?\\C:\\",
|
||||
L"C:\\",
|
||||
TRUE,
|
||||
},
|
||||
{
|
||||
L"\\\\?\\C:\\",
|
||||
L"C:\\",
|
||||
TRUE,
|
||||
},
|
||||
{ 0, }
|
||||
};
|
||||
|
||||
for (i = 0; testcases[i].in; i++)
|
||||
{
|
||||
gsize str_len = wcslen (testcases[i].in) + 1;
|
||||
gchar *in_u8 = g_utf16_to_utf8 (testcases[i].in, -1, NULL, NULL, NULL);
|
||||
gchar *out_u8 = g_utf16_to_utf8 (testcases[i].out, -1, NULL, NULL, NULL);
|
||||
|
||||
g_assert_nonnull (in_u8);
|
||||
g_assert_nonnull (out_u8);
|
||||
|
||||
buf = g_new0 (gunichar2, str_len);
|
||||
memcpy (buf, testcases[i].in, str_len * sizeof (gunichar2));
|
||||
_g_win32_strip_extended_ntobjm_prefix (buf, &str_len);
|
||||
g_assert_cmpwcs (buf, ==, testcases[i].out, in_u8, out_u8);
|
||||
g_free (buf);
|
||||
g_free (in_u8);
|
||||
g_free (out_u8);
|
||||
}
|
||||
/* Check for correct behaviour on non-NUL-terminated strings */
|
||||
for (i = 0; testcases[i].in; i++)
|
||||
{
|
||||
gsize str_len = wcslen (testcases[i].in) + 1;
|
||||
wchar_t old_endchar;
|
||||
gchar *in_u8 = g_utf16_to_utf8 (testcases[i].in, -1, NULL, NULL, NULL);
|
||||
gchar *out_u8 = g_utf16_to_utf8 (testcases[i].out, -1, NULL, NULL, NULL);
|
||||
|
||||
g_assert_nonnull (in_u8);
|
||||
g_assert_nonnull (out_u8);
|
||||
|
||||
buf = g_new0 (gunichar2, str_len);
|
||||
memcpy (buf, testcases[i].in, (str_len) * sizeof (gunichar2));
|
||||
|
||||
old_endchar = buf[wcslen (testcases[i].out)];
|
||||
str_len -= 1;
|
||||
|
||||
if (testcases[i].result)
|
||||
{
|
||||
/* Given "\\\\?\\C:\\" (len 7, unterminated),
|
||||
* we should get "C:\\" (len 3, unterminated).
|
||||
* Put a character different from "\\" (4-th character of the buffer)
|
||||
* at the end of the unterminated source buffer, into a position
|
||||
* where NUL-terminator would normally be. Then later test that 4-th character
|
||||
* in the buffer is still the old "\\".
|
||||
* After that terminate the string and use normal g_wcscmp0().
|
||||
*/
|
||||
buf[str_len] = old_endchar - 1;
|
||||
}
|
||||
|
||||
_g_win32_strip_extended_ntobjm_prefix (buf, &str_len);
|
||||
g_assert_cmpuint (old_endchar, ==, buf[wcslen (testcases[i].out)]);
|
||||
buf[str_len] = L'\0';
|
||||
g_assert_cmpwcs (buf, ==, testcases[i].out, in_u8, out_u8);
|
||||
g_free (buf);
|
||||
g_free (in_u8);
|
||||
g_free (out_u8);
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
@ -1018,6 +1151,9 @@ main (int argc,
|
||||
|
||||
g_test_bug_base ("https://gitlab.gnome.org/GNOME/glib/merge_requests/");
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
g_test_add_func ("/fileutils/stdio-win32-pathstrip", test_win32_pathstrip);
|
||||
#endif
|
||||
g_test_add_func ("/fileutils/build-path", test_build_path);
|
||||
g_test_add_func ("/fileutils/build-pathv", test_build_pathv);
|
||||
g_test_add_func ("/fileutils/build-filename", test_build_filename);
|
||||
|
Loading…
Reference in New Issue
Block a user