(root)/
glib-2.79.0/
gio/
gwin32volumemonitor.c
       1  /* GIO - GLib Input, Output and Streaming Library
       2   * 
       3   * Copyright (C) 2006-2007 Red Hat, Inc.
       4   * Copyright (C) 2008 Hans Breuer
       5   *
       6   * SPDX-License-Identifier: LGPL-2.1-or-later
       7   *
       8   * This library is free software; you can redistribute it and/or
       9   * modify it under the terms of the GNU Lesser General Public
      10   * License as published by the Free Software Foundation; either
      11   * version 2.1 of the License, or (at your option) any later version.
      12   *
      13   * This library is distributed in the hope that it will be useful,
      14   * but WITHOUT ANY WARRANTY; without even the implied warranty of
      15   * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
      16   * Lesser General Public License for more details.
      17   *
      18   * You should have received a copy of the GNU Lesser General
      19   * Public License along with this library; if not, see <http://www.gnu.org/licenses/>.
      20   *
      21   * Author: Alexander Larsson <alexl@redhat.com>
      22   *         David Zeuthen <davidz@redhat.com>
      23   *         Hans Breuer <hans@breuer.org>
      24   */
      25  
      26  #include "config.h"
      27  
      28  #include <string.h>
      29  
      30  #include <glib.h>
      31  #include "glibintl.h"
      32  
      33  #include "gwin32volumemonitor.h"
      34  #include "gwin32mount.h"
      35  #include "gmount.h"
      36  #include "giomodule.h"
      37  
      38  #include <windows.h>
      39  
      40  struct _GWin32VolumeMonitor {
      41    GNativeVolumeMonitor parent;
      42  };
      43  
      44  #define g_win32_volume_monitor_get_type _g_win32_volume_monitor_get_type
      45  G_DEFINE_TYPE_WITH_CODE (GWin32VolumeMonitor, g_win32_volume_monitor, G_TYPE_NATIVE_VOLUME_MONITOR,
      46                           g_io_extension_point_implement (G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME,
      47  							 g_define_type_id,
      48  							 "win32",
      49  							 0));
      50  							 
      51  /**
      52   * get_viewable_logical_drives:
      53   *
      54   * Returns the list of logical and viewable drives as defined by
      55   * GetLogicalDrives() and the registry keys
      56   * Software\Microsoft\Windows\CurrentVersion\Policies\Explorer under
      57   * HKLM or HKCU. If neither key exists the result of
      58   * GetLogicalDrives() is returned.
      59   *
      60   * Returns: bitmask with same meaning as returned by GetLogicalDrives()
      61   */
      62  static guint32 
      63  get_viewable_logical_drives (void)
      64  {
      65    guint viewable_drives = GetLogicalDrives ();
      66    HKEY key;
      67  
      68    DWORD var_type = REG_DWORD; //the value's a REG_DWORD type
      69    DWORD no_drives_size = 4;
      70    DWORD no_drives;
      71    gboolean hklm_present = FALSE;
      72  
      73    if (RegOpenKeyExW (HKEY_LOCAL_MACHINE,
      74  		     L"Software\\Microsoft\\Windows\\"
      75  		     L"CurrentVersion\\Policies\\Explorer",
      76  		     0, KEY_READ, &key) == ERROR_SUCCESS)
      77      {
      78        if (RegQueryValueExW (key, L"NoDrives", NULL, &var_type,
      79  			    (LPBYTE) &no_drives, &no_drives_size) == ERROR_SUCCESS)
      80  	{
      81  	  /* We need the bits that are set in viewable_drives, and
      82  	   * unset in no_drives.
      83  	   */
      84  	  viewable_drives = viewable_drives & ~no_drives;
      85  	  hklm_present = TRUE;
      86  	}
      87        RegCloseKey (key);
      88      }
      89  
      90    /* If the key is present in HKLM then the one in HKCU should be ignored */
      91    if (!hklm_present)
      92      {
      93        if (RegOpenKeyExW (HKEY_CURRENT_USER,
      94  			 L"Software\\Microsoft\\Windows\\"
      95  			 L"CurrentVersion\\Policies\\Explorer",
      96  			 0, KEY_READ, &key) == ERROR_SUCCESS)
      97  	{
      98  	  if (RegQueryValueExW (key, L"NoDrives", NULL, &var_type,
      99  			        (LPBYTE) &no_drives, &no_drives_size) == ERROR_SUCCESS)
     100  	    {
     101  	      viewable_drives = viewable_drives & ~no_drives;
     102  	    }
     103  	  RegCloseKey (key);
     104  	}
     105      }
     106  
     107    return viewable_drives; 
     108  }
     109  
     110  /* deliver accessible (aka 'mounted') volumes */
     111  static GList *
     112  get_mounts (GVolumeMonitor *volume_monitor)
     113  {
     114    DWORD   drives;
     115    gchar   drive[4] = "A:\\";
     116    GQueue  queue = G_QUEUE_INIT;
     117    
     118    drives = get_viewable_logical_drives ();
     119  
     120    if (!drives)
     121      g_warning ("get_viewable_logical_drives failed.");
     122  
     123    while (drives && drive[0] <= 'Z')
     124      {
     125        if (drives & 1)
     126          g_queue_push_tail (&queue, _g_win32_mount_new (volume_monitor, drive, NULL));
     127  
     128        drives >>= 1;
     129        drive[0]++;
     130      }
     131  
     132    return g_steal_pointer (&queue.head);
     133  }
     134  
     135  /* actually 'mounting' volumes is out of GIOs business on win32, so no volumes are delivered either */
     136  static GList *
     137  get_volumes (GVolumeMonitor *volume_monitor)
     138  {
     139    return NULL;
     140  }
     141  
     142  /* real hardware */
     143  static GList *
     144  get_connected_drives (GVolumeMonitor *volume_monitor)
     145  {
     146    GList *list = NULL;
     147  
     148  #if 0
     149    HANDLE  find_handle;
     150    BOOL    found;
     151    wchar_t wc_name[MAX_PATH+1];
     152    
     153    find_handle = FindFirstVolumeW (wc_name, MAX_PATH);
     154    found = (find_handle != INVALID_HANDLE_VALUE);
     155    while (found)
     156      {
     157        /* I don't know what this code is supposed to do; clearly it now
     158         * does nothing, the returned GList is always NULL. But what was
     159         * this code supposed to be a start of? The volume names that
     160         * the FindFirstVolume/FindNextVolume loop iterates over returns
     161         * device names like
     162         *
     163         *   \Device\HarddiskVolume1
     164         *   \Device\HarddiskVolume2
     165         *   \Device\CdRom0
     166         *
     167         * No DOS devices there, so I don't see the point with the
     168         * QueryDosDevice call below. Probably this code is confusing volumes
     169         * with something else that does contain the mapping from DOS devices
     170         * to volumes.
     171         */
     172        wchar_t wc_dev_name[MAX_PATH+1];
     173        guint trailing = wcslen (wc_name) - 1;
     174  
     175        /* remove trailing backslash and leading \\?\\ */
     176        wc_name[trailing] = L'\0';
     177        if (QueryDosDeviceW (&wc_name[4], wc_dev_name, MAX_PATH))
     178          {
     179            gchar *name = g_utf16_to_utf8 (wc_dev_name, -1, NULL, NULL, NULL);
     180            g_print ("%s\n", name);
     181  	  g_free (name);
     182  	}
     183  
     184        found = FindNextVolumeW (find_handle, wc_name, MAX_PATH);
     185      }
     186    if (find_handle != INVALID_HANDLE_VALUE)
     187      FindVolumeClose (find_handle);
     188  #endif
     189  
     190    return list;
     191  }
     192  
     193  static GVolume *
     194  get_volume_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
     195  {
     196    return NULL;
     197  }
     198  
     199  static GMount *
     200  get_mount_for_uuid (GVolumeMonitor *volume_monitor, const char *uuid)
     201  {
     202    return NULL;
     203  }
     204  
     205  static gboolean
     206  is_supported (void)
     207  {
     208    return TRUE;
     209  }
     210  
     211  static GMount *
     212  get_mount_for_mount_path (const char *mount_path,
     213                            GCancellable *cancellable)
     214  {
     215    GWin32Mount *mount;
     216  
     217    /* TODO: Set mountable volume? */
     218    mount = _g_win32_mount_new (NULL, mount_path, NULL);
     219  
     220    return G_MOUNT (mount);
     221  }
     222  
     223  static void
     224  g_win32_volume_monitor_class_init (GWin32VolumeMonitorClass *klass)
     225  {
     226    GVolumeMonitorClass *monitor_class = G_VOLUME_MONITOR_CLASS (klass);
     227    GNativeVolumeMonitorClass *native_class = G_NATIVE_VOLUME_MONITOR_CLASS (klass);
     228    
     229    monitor_class->get_mounts = get_mounts;
     230    monitor_class->get_volumes = get_volumes;
     231    monitor_class->get_connected_drives = get_connected_drives;
     232    monitor_class->get_volume_for_uuid = get_volume_for_uuid;
     233    monitor_class->get_mount_for_uuid = get_mount_for_uuid;
     234    monitor_class->is_supported = is_supported;
     235  
     236    native_class->get_mount_for_mount_path = get_mount_for_mount_path;
     237  }
     238  
     239  static void
     240  g_win32_volume_monitor_init (GWin32VolumeMonitor *win32_monitor)
     241  {
     242    /* maybe we should setup a callback window to listen for WM_DEVICECHANGE ? */
     243  #if 0
     244    unix_monitor->mount_monitor = g_win32_mount_monitor_new ();
     245  
     246    g_signal_connect (win32_monitor->mount_monitor,
     247  		    "mounts-changed", G_CALLBACK (mounts_changed),
     248  		    win32_monitor);
     249    
     250    g_signal_connect (win32_monitor->mount_monitor,
     251  		    "mountpoints-changed", G_CALLBACK (mountpoints_changed),
     252  		    win32_monitor);
     253  		    
     254    update_volumes (win32_monitor);
     255    update_mounts (win32_monitor);
     256  #endif
     257  }