mirror of
				https://gitlab.gnome.org/GNOME/glib.git
				synced 2025-11-04 01:58:54 +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);
 | 
						|
}
 |