mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-10-31 16:32:18 +01:00 
			
		
		
		
	Basically various trivial instances of the following MSVC compiler warning: ``` ../gio/gio-tool-set.c(50): warning C4267: '=': conversion from 'size_t' to 'int', possible loss of data ``` Signed-off-by: Philip Withnall <pwithnall@gnome.org>
		
			
				
	
	
		
			427 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			427 lines
		
	
	
		
			16 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| /* GIO - GLib Input, Output and Streaming Library
 | |
|  *
 | |
|  * Copyright (C) 2006-2007 Red Hat, Inc.
 | |
|  * Copyright (C) 2015 Chun-wei Fan
 | |
|  *
 | |
|  * 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/>.
 | |
|  *
 | |
|  * Author: Vlad Grecescu <b100dian@gmail.com>
 | |
|  * Author: Chun-wei Fan <fanc999@yahoo.com.tw>
 | |
|  *
 | |
|  */
 | |
| 
 | |
| #include "config.h"
 | |
| 
 | |
| #include "gwin32fsmonitorutils.h"
 | |
| #include "gio/gfile.h"
 | |
| 
 | |
| #include <windows.h>
 | |
| 
 | |
| #define MAX_PATH_LONG 32767 /* Support Paths longer than MAX_PATH (260) characters */
 | |
| 
 | |
| static gboolean
 | |
| g_win32_fs_monitor_handle_event (GWin32FSMonitorPrivate   *monitor,
 | |
|                                  const gchar              *filename,
 | |
|                                  PFILE_NOTIFY_INFORMATION  pfni)
 | |
| {
 | |
|   GFileMonitorEvent fme;
 | |
|   PFILE_NOTIFY_INFORMATION pfni_next;
 | |
|   WIN32_FILE_ATTRIBUTE_DATA attrib_data = {0, };
 | |
|   gchar *renamed_file = NULL;
 | |
| 
 | |
|   switch (pfni->Action)
 | |
|     {
 | |
|     case FILE_ACTION_ADDED:
 | |
|       fme = G_FILE_MONITOR_EVENT_CREATED;
 | |
|       break;
 | |
| 
 | |
|     case FILE_ACTION_REMOVED:
 | |
|       fme = G_FILE_MONITOR_EVENT_DELETED;
 | |
|       break;
 | |
| 
 | |
|     case FILE_ACTION_MODIFIED:
 | |
|       {
 | |
|         gboolean success_attribs = GetFileAttributesExW (monitor->wfullpath_with_long_prefix,
 | |
|                                                          GetFileExInfoStandard,
 | |
|                                                          &attrib_data);
 | |
| 
 | |
|         if (monitor->file_attribs != INVALID_FILE_ATTRIBUTES &&
 | |
|             success_attribs &&
 | |
|             attrib_data.dwFileAttributes != monitor->file_attribs)
 | |
|           fme = G_FILE_MONITOR_EVENT_ATTRIBUTE_CHANGED;
 | |
|         else
 | |
|           fme = G_FILE_MONITOR_EVENT_CHANGED;
 | |
| 
 | |
|         monitor->file_attribs = attrib_data.dwFileAttributes;
 | |
|       }
 | |
|       break;
 | |
| 
 | |
|     case FILE_ACTION_RENAMED_OLD_NAME:
 | |
|       if (pfni->NextEntryOffset != 0)
 | |
|         {
 | |
|           /* If the file was renamed in the same directory, we would get a
 | |
|            * FILE_ACTION_RENAMED_NEW_NAME action in the next FILE_NOTIFY_INFORMATION
 | |
|            * structure.
 | |
|            */
 | |
|           glong file_name_len = 0;
 | |
| 
 | |
|           pfni_next = (PFILE_NOTIFY_INFORMATION) ((BYTE*)pfni + pfni->NextEntryOffset);
 | |
|           renamed_file = g_utf16_to_utf8 (pfni_next->FileName, pfni_next->FileNameLength / sizeof(WCHAR), NULL, &file_name_len, NULL);
 | |
|           if (pfni_next->Action == FILE_ACTION_RENAMED_NEW_NAME)
 | |
|            fme = G_FILE_MONITOR_EVENT_RENAMED;
 | |
|           else
 | |
|            fme = G_FILE_MONITOR_EVENT_MOVED_OUT;
 | |
|         }
 | |
|       else
 | |
|         fme = G_FILE_MONITOR_EVENT_MOVED_OUT;
 | |
|       break;
 | |
| 
 | |
|     case FILE_ACTION_RENAMED_NEW_NAME:
 | |
|       if (monitor->pfni_prev != NULL &&
 | |
|           monitor->pfni_prev->Action == FILE_ACTION_RENAMED_OLD_NAME)
 | |
|         {
 | |
|           /* don't bother sending events, was already sent (rename) */
 | |
|           fme = (GFileMonitorEvent) -1;
 | |
|         }
 | |
|       else
 | |
|         fme = G_FILE_MONITOR_EVENT_MOVED_IN;
 | |
|       break;
 | |
| 
 | |
|     default:
 | |
|       /* The possible Windows actions are all above, so shouldn't get here */
 | |
|       g_assert_not_reached ();
 | |
|       break;
 | |
|     }
 | |
| 
 | |
|   if (fme != (GFileMonitorEvent) -1)
 | |
|     return g_file_monitor_source_handle_event (monitor->fms,
 | |
|                                                fme,
 | |
|                                                filename,
 | |
|                                                renamed_file,
 | |
|                                                NULL,
 | |
|                                                g_get_monotonic_time ());
 | |
|   else
 | |
|     return FALSE;
 | |
| }
 | |
| 
 | |
| 
 | |
| static void CALLBACK
 | |
| g_win32_fs_monitor_callback (DWORD        error,
 | |
|                              DWORD        nBytes,
 | |
|                              LPOVERLAPPED lpOverlapped)
 | |
| {
 | |
|   gulong offset;
 | |
|   PFILE_NOTIFY_INFORMATION pfile_notify_walker;
 | |
|   GWin32FSMonitorPrivate *monitor = (GWin32FSMonitorPrivate *) lpOverlapped;
 | |
| 
 | |
|   DWORD notify_filter = monitor->isfile ?
 | |
|                         (FILE_NOTIFY_CHANGE_FILE_NAME |
 | |
|                          FILE_NOTIFY_CHANGE_ATTRIBUTES |
 | |
|                          FILE_NOTIFY_CHANGE_SIZE) :
 | |
|                         (FILE_NOTIFY_CHANGE_FILE_NAME |
 | |
|                          FILE_NOTIFY_CHANGE_DIR_NAME |
 | |
|                          FILE_NOTIFY_CHANGE_ATTRIBUTES |
 | |
|                          FILE_NOTIFY_CHANGE_SIZE);
 | |
| 
 | |
|   /* If monitor->self is NULL the GWin32FileMonitor object has been destroyed. */
 | |
|   if (monitor->self == NULL ||
 | |
|       g_file_monitor_is_cancelled (monitor->self) ||
 | |
|       monitor->file_notify_buffer == NULL)
 | |
|     {
 | |
|       g_free (monitor->file_notify_buffer);
 | |
|       g_free (monitor);
 | |
|       return;
 | |
|     }
 | |
| 
 | |
|   offset = 0;
 | |
| 
 | |
|   do
 | |
|     {
 | |
|       pfile_notify_walker = (PFILE_NOTIFY_INFORMATION)((BYTE *)monitor->file_notify_buffer + offset);
 | |
|       if (pfile_notify_walker->Action > 0)
 | |
|         {
 | |
|           glong file_name_len;
 | |
|           gchar *changed_file;
 | |
| 
 | |
|           changed_file = g_utf16_to_utf8 (pfile_notify_walker->FileName,
 | |
|                                           pfile_notify_walker->FileNameLength / sizeof(WCHAR),
 | |
|                                           NULL, &file_name_len, NULL);
 | |
| 
 | |
|           if (monitor->isfile)
 | |
|             {
 | |
|               size_t long_filename_length = wcslen (monitor->wfilename_long);
 | |
|               size_t short_filename_length = wcslen (monitor->wfilename_short);
 | |
|               enum GWin32FileMonitorFileAlias alias_state;
 | |
| 
 | |
|               /* If monitoring a file, check that the changed file
 | |
|               * in the directory matches the file that is to be monitored
 | |
|               * We need to check both the long and short file names for the same file.
 | |
|               *
 | |
|               * We need to send in the name of the monitored file, not its long (or short) variant,
 | |
|               * if they exist.
 | |
|               */
 | |
| 
 | |
|               if (_wcsnicmp (pfile_notify_walker->FileName,
 | |
|                              monitor->wfilename_long,
 | |
|                              long_filename_length) == 0)
 | |
|                 {
 | |
|                   if (_wcsnicmp (pfile_notify_walker->FileName,
 | |
|                                  monitor->wfilename_short,
 | |
|                                  short_filename_length) == 0)
 | |
|                     {
 | |
|                       alias_state = G_WIN32_FILE_MONITOR_NO_ALIAS;
 | |
|                     }
 | |
|                   else
 | |
|                     alias_state = G_WIN32_FILE_MONITOR_LONG_FILENAME;
 | |
|                 }
 | |
|               else if (_wcsnicmp (pfile_notify_walker->FileName,
 | |
|                                   monitor->wfilename_short,
 | |
|                                   short_filename_length) == 0)
 | |
|                 {
 | |
|                   alias_state = G_WIN32_FILE_MONITOR_SHORT_FILENAME;
 | |
|                 }
 | |
|               else
 | |
|                 alias_state = G_WIN32_FILE_MONITOR_NO_MATCH_FOUND;
 | |
| 
 | |
|               if (alias_state != G_WIN32_FILE_MONITOR_NO_MATCH_FOUND)
 | |
|                 {
 | |
|                   wchar_t *monitored_file_w;
 | |
|                   gchar *monitored_file;
 | |
| 
 | |
|                   switch (alias_state)
 | |
|                     {
 | |
|                     case G_WIN32_FILE_MONITOR_NO_ALIAS:
 | |
|                       monitored_file = g_strdup (changed_file);
 | |
|                       break;
 | |
|                     case G_WIN32_FILE_MONITOR_LONG_FILENAME:
 | |
|                     case G_WIN32_FILE_MONITOR_SHORT_FILENAME:
 | |
|                       monitored_file_w = wcsrchr (monitor->wfullpath_with_long_prefix, L'\\');
 | |
|                       monitored_file = g_utf16_to_utf8 (monitored_file_w + 1, -1, NULL, NULL, NULL);
 | |
|                       break;
 | |
|                     default:
 | |
|                       g_assert_not_reached ();
 | |
|                       break;
 | |
|                     }
 | |
| 
 | |
|                   g_win32_fs_monitor_handle_event (monitor, monitored_file, pfile_notify_walker);
 | |
|                   g_free (monitored_file);
 | |
|                 }
 | |
|             }
 | |
|           else
 | |
|             g_win32_fs_monitor_handle_event (monitor, changed_file, pfile_notify_walker);
 | |
| 
 | |
|           g_free (changed_file);
 | |
|         }
 | |
| 
 | |
|       monitor->pfni_prev = pfile_notify_walker;
 | |
|       offset += pfile_notify_walker->NextEntryOffset;
 | |
|     }
 | |
|   while (pfile_notify_walker->NextEntryOffset);
 | |
| 
 | |
|   ReadDirectoryChangesW (monitor->hDirectory,
 | |
|                          monitor->file_notify_buffer,
 | |
|                          monitor->buffer_allocated_bytes,
 | |
|                          FALSE,
 | |
|                          notify_filter,
 | |
|                          &monitor->buffer_filled_bytes,
 | |
|                          &monitor->overlapped,
 | |
|                          g_win32_fs_monitor_callback);
 | |
| }
 | |
| 
 | |
| void
 | |
| g_win32_fs_monitor_init (GWin32FSMonitorPrivate *monitor,
 | |
|                          const gchar *dirname,
 | |
|                          const gchar *filename,
 | |
|                          gboolean isfile)
 | |
| {
 | |
|   wchar_t *wdirname_with_long_prefix = NULL;
 | |
|   const gchar LONGPFX[] = "\\\\?\\";
 | |
|   gchar *fullpath_with_long_prefix, *dirname_with_long_prefix;
 | |
|   DWORD notify_filter = isfile ?
 | |
|                         (FILE_NOTIFY_CHANGE_FILE_NAME |
 | |
|                          FILE_NOTIFY_CHANGE_ATTRIBUTES |
 | |
|                          FILE_NOTIFY_CHANGE_SIZE) :
 | |
|                         (FILE_NOTIFY_CHANGE_FILE_NAME |
 | |
|                          FILE_NOTIFY_CHANGE_DIR_NAME |
 | |
|                          FILE_NOTIFY_CHANGE_ATTRIBUTES |
 | |
|                          FILE_NOTIFY_CHANGE_SIZE);
 | |
| 
 | |
|   gboolean success_attribs;
 | |
|   WIN32_FILE_ATTRIBUTE_DATA attrib_data = {0, };
 | |
| 
 | |
| 
 | |
|   if (dirname != NULL)
 | |
|     {
 | |
|       dirname_with_long_prefix = g_strconcat (LONGPFX, dirname, NULL);
 | |
|       wdirname_with_long_prefix = g_utf8_to_utf16 (dirname_with_long_prefix, -1, NULL, NULL, NULL);
 | |
| 
 | |
|       if (isfile)
 | |
|         {
 | |
|           gchar *fullpath;
 | |
|           wchar_t wlongname[MAX_PATH_LONG];
 | |
|           wchar_t wshortname[MAX_PATH_LONG];
 | |
|           wchar_t *wfullpath, *wbasename_long, *wbasename_short;
 | |
| 
 | |
|           fullpath = g_build_filename (dirname, filename, NULL);
 | |
|           fullpath_with_long_prefix = g_strconcat (LONGPFX, fullpath, NULL);
 | |
| 
 | |
|           wfullpath = g_utf8_to_utf16 (fullpath, -1, NULL, NULL, NULL);
 | |
| 
 | |
|           monitor->wfullpath_with_long_prefix =
 | |
|             g_utf8_to_utf16 (fullpath_with_long_prefix, -1, NULL, NULL, NULL);
 | |
| 
 | |
|           /* ReadDirectoryChangesW() can return the normal filename or the
 | |
|            * "8.3" format filename, so we need to keep track of both these names
 | |
|            * so that we can check against them later when it returns
 | |
|            */
 | |
|           if (GetLongPathNameW (monitor->wfullpath_with_long_prefix, wlongname, MAX_PATH_LONG) == 0)
 | |
|             {
 | |
|               wbasename_long = wcsrchr (monitor->wfullpath_with_long_prefix, L'\\');
 | |
|               monitor->wfilename_long = wbasename_long != NULL ?
 | |
|                                         wcsdup (wbasename_long + 1) :
 | |
|                                         wcsdup (wfullpath);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               wbasename_long = wcsrchr (wlongname, L'\\');
 | |
|               monitor->wfilename_long = wbasename_long != NULL ?
 | |
|                                         wcsdup (wbasename_long + 1) :
 | |
|                                         wcsdup (wlongname);
 | |
| 
 | |
|             }
 | |
| 
 | |
|           if (GetShortPathNameW (monitor->wfullpath_with_long_prefix, wshortname, MAX_PATH_LONG) == 0)
 | |
|             {
 | |
|               wbasename_short = wcsrchr (monitor->wfullpath_with_long_prefix, L'\\');
 | |
|               monitor->wfilename_short = wbasename_short != NULL ?
 | |
|                                          wcsdup (wbasename_short + 1) :
 | |
|                                          wcsdup (wfullpath);
 | |
|             }
 | |
|           else
 | |
|             {
 | |
|               wbasename_short = wcsrchr (wshortname, L'\\');
 | |
|               monitor->wfilename_short = wbasename_short != NULL ?
 | |
|                                          wcsdup (wbasename_short + 1) :
 | |
|                                          wcsdup (wshortname);
 | |
|             }
 | |
| 
 | |
|           g_free (wfullpath);
 | |
|           g_free (fullpath);
 | |
|         }
 | |
|       else
 | |
|         {
 | |
|           monitor->wfilename_short = NULL;
 | |
|           monitor->wfilename_long = NULL;
 | |
|           monitor->wfullpath_with_long_prefix = g_utf8_to_utf16 (dirname_with_long_prefix, -1, NULL, NULL, NULL);
 | |
|         }
 | |
| 
 | |
|       monitor->isfile = isfile;
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       dirname_with_long_prefix = g_strconcat (LONGPFX, filename, NULL);
 | |
|       monitor->wfullpath_with_long_prefix = g_utf8_to_utf16 (dirname_with_long_prefix, -1, NULL, NULL, NULL);
 | |
|       monitor->wfilename_long = NULL;
 | |
|       monitor->wfilename_short = NULL;
 | |
|       monitor->isfile = FALSE;
 | |
|     }
 | |
| 
 | |
|   success_attribs = GetFileAttributesExW (monitor->wfullpath_with_long_prefix,
 | |
|                                           GetFileExInfoStandard,
 | |
|                                           &attrib_data);
 | |
|   if (success_attribs)
 | |
|     monitor->file_attribs = attrib_data.dwFileAttributes; /* Store up original attributes */
 | |
|   else
 | |
|     monitor->file_attribs = INVALID_FILE_ATTRIBUTES;
 | |
|   monitor->pfni_prev = NULL;
 | |
|   monitor->hDirectory = CreateFileW (wdirname_with_long_prefix != NULL ? wdirname_with_long_prefix : monitor->wfullpath_with_long_prefix,
 | |
|                                      FILE_LIST_DIRECTORY,
 | |
|                                      FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE,
 | |
|                                      NULL,
 | |
|                                      OPEN_EXISTING,
 | |
|                                      FILE_FLAG_BACKUP_SEMANTICS | FILE_FLAG_OVERLAPPED,
 | |
|                                      NULL);
 | |
| 
 | |
|   g_free (wdirname_with_long_prefix);
 | |
|   g_free (dirname_with_long_prefix);
 | |
| 
 | |
|   if (monitor->hDirectory != INVALID_HANDLE_VALUE)
 | |
|     {
 | |
|       ReadDirectoryChangesW (monitor->hDirectory,
 | |
|                              monitor->file_notify_buffer,
 | |
|                              monitor->buffer_allocated_bytes,
 | |
|                              FALSE,
 | |
|                              notify_filter,
 | |
|                              &monitor->buffer_filled_bytes,
 | |
|                              &monitor->overlapped,
 | |
|                              g_win32_fs_monitor_callback);
 | |
|     }
 | |
| }
 | |
| 
 | |
| GWin32FSMonitorPrivate *
 | |
| g_win32_fs_monitor_create (gboolean isfile)
 | |
| {
 | |
|   GWin32FSMonitorPrivate *monitor = g_new0 (GWin32FSMonitorPrivate, 1);
 | |
| 
 | |
|   monitor->buffer_allocated_bytes = 32784;
 | |
|   monitor->file_notify_buffer = g_new0 (FILE_NOTIFY_INFORMATION, monitor->buffer_allocated_bytes);
 | |
| 
 | |
|   return monitor;
 | |
| }
 | |
| 
 | |
| void
 | |
| g_win32_fs_monitor_finalize (GWin32FSMonitorPrivate *monitor)
 | |
| {
 | |
|   g_free (monitor->wfullpath_with_long_prefix);
 | |
|   g_free (monitor->wfilename_long);
 | |
|   g_free (monitor->wfilename_short);
 | |
| 
 | |
|   if (monitor->hDirectory == INVALID_HANDLE_VALUE)
 | |
|     {
 | |
|       /* If we don't have a directory handle we can free
 | |
|        * monitor->file_notify_buffer and monitor here. The
 | |
|        * callback won't be called obviously any more (and presumably
 | |
|        * never has been called).
 | |
|        */
 | |
|       g_free (monitor->file_notify_buffer);
 | |
|       monitor->file_notify_buffer = NULL;
 | |
|       g_free (monitor);
 | |
|     }
 | |
|   else
 | |
|     {
 | |
|       /* If we have a directory handle, the OVERLAPPED struct is
 | |
|        * passed once more to the callback as a result of the
 | |
|        * CloseHandle() done in the cancel method, so monitor has to
 | |
|        * be kept around. The GWin32DirectoryMonitor object is
 | |
|        * disappearing, so can't leave a pointer to it in
 | |
|        * monitor->self.
 | |
|        */
 | |
|       monitor->self = NULL;
 | |
|     }
 | |
| }
 | |
| 
 | |
| void
 | |
| g_win32_fs_monitor_close_handle (GWin32FSMonitorPrivate *monitor)
 | |
| {
 | |
|   /* This triggers a last callback() with nBytes==0. */
 | |
| 
 | |
|   /* Actually I am not so sure about that, it seems to trigger a last
 | |
|    * callback correctly, but the way to recognize that it is the final
 | |
|    * one is not to check for nBytes==0, I think that was a
 | |
|    * misunderstanding.
 | |
|    */
 | |
|   if (monitor->hDirectory != INVALID_HANDLE_VALUE)
 | |
|     CloseHandle (monitor->hDirectory);
 | |
| }
 |