mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-25 06:22:15 +02:00 
			
		
		
		
	Merge branch 'w32-gfileinfo-improvements' into 'master'
W32 GFileInfo improvements See merge request GNOME/glib!238
This commit is contained in:
		| @@ -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); | ||||
|   | ||||
		Reference in New Issue
	
	Block a user