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