VTB: release CVBuffer after it actually has been rendered
[xbmc.git] / xbmc / storage / linux / UDisksProvider.cpp
blob7bdc5209f6826e8bcb3efd884ed7e4bb90608de4
1 /*
2 * Copyright (C) 2005-2015 Team Kodi
3 * http://kodi.tv
5 * This Program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2, or (at your option)
8 * any later version.
10 * This Program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
15 * You should have received a copy of the GNU General Public License
16 * along with Kodi; see the file COPYING. If not, see
17 * <http://www.gnu.org/licenses/>.
20 #include "UDisksProvider.h"
21 #ifdef HAS_DBUS
22 #include "settings/AdvancedSettings.h"
23 #include "guilib/LocalizeStrings.h"
24 #include "utils/log.h"
25 #include "utils/StringUtils.h"
26 #include "utils/URIUtils.h"
27 #include "PosixMountProvider.h"
29 CUDiskDevice::CUDiskDevice(const char *DeviceKitUDI):
30 m_DeviceKitUDI(DeviceKitUDI)
32 m_isMounted = false;
33 m_isMountedByUs = false;
34 m_isRemovable = false;
35 m_isPartition = false;
36 m_isFileSystem = false;
37 m_isSystemInternal = false;
38 m_isOptical = false;
39 m_PartitionSize = 0;
40 Update();
43 void CUDiskDevice::Update()
45 CVariant properties = CDBusUtil::GetAll("org.freedesktop.UDisks", m_DeviceKitUDI.c_str(), "org.freedesktop.UDisks.Device");
47 m_isFileSystem = properties["IdUsage"].asString() == "filesystem";
48 if (m_isFileSystem)
50 m_UDI = properties["IdUuid"].asString();
51 m_Label = properties["IdLabel"].asString();
52 m_FileSystem = properties["IdType"].asString();
54 else
56 m_UDI.clear();
57 m_Label.clear();
58 m_FileSystem.clear();
61 m_isMounted = properties["DeviceIsMounted"].asBoolean();
62 if (m_isMounted && !properties["DeviceMountPaths"].empty())
63 m_MountPath = properties["DeviceMountPaths"][0].asString();
64 else
65 m_MountPath.clear();
67 m_PartitionSize = properties["PartitionSize"].asUnsignedInteger();
68 m_isPartition = properties["DeviceIsPartition"].asBoolean();
69 m_isSystemInternal = properties["DeviceIsSystemInternal"].asBoolean();
70 m_isOptical = properties["DeviceIsOpticalDisc"].asBoolean();
71 if (m_isPartition)
73 CVariant isRemovable = CDBusUtil::GetVariant("org.freedesktop.UDisks", properties["PartitionSlave"].asString().c_str(), "org.freedesktop.UDisks.Device", "DeviceIsRemovable");
75 if ( !isRemovable.isNull() )
76 m_isRemovable = isRemovable.asBoolean();
77 else
78 m_isRemovable = false;
80 else
81 m_isRemovable = properties["DeviceIsRemovable"].asBoolean();
84 bool CUDiskDevice::Mount()
86 if (!m_isMounted && !m_isSystemInternal && m_isFileSystem)
88 CLog::Log(LOGDEBUG, "UDisks: Mounting %s", m_DeviceKitUDI.c_str());
89 CDBusMessage message("org.freedesktop.UDisks", m_DeviceKitUDI.c_str(), "org.freedesktop.UDisks.Device", "FilesystemMount");
90 message.AppendArgument("");
91 const char *array[] = {};
92 message.AppendArgument(array, 0);
94 DBusMessage *reply = message.SendSystem();
95 if (reply)
97 char *mountPoint;
98 if (dbus_message_get_args (reply, NULL, DBUS_TYPE_STRING, &mountPoint, DBUS_TYPE_INVALID))
100 m_MountPath = mountPoint;
101 CLog::Log(LOGDEBUG, "UDisks: Successfully mounted %s on %s", m_DeviceKitUDI.c_str(), mountPoint);
102 m_isMountedByUs = m_isMounted = true;
106 return m_isMounted;
108 else
109 CLog::Log(LOGDEBUG, "UDisks: Is not able to mount %s", toString().c_str());
111 return false;
114 bool CUDiskDevice::UnMount()
116 if (m_isMounted && !m_isSystemInternal && m_isFileSystem)
118 CDBusMessage message("org.freedesktop.UDisks", m_DeviceKitUDI.c_str(), "org.freedesktop.UDisks.Device", "FilesystemUnmount");
120 const char *array[1];
121 message.AppendArgument(array, 0);
123 DBusMessage *reply = message.SendSystem();
124 if (reply)
125 m_isMountedByUs = m_isMounted = false;
127 return !m_isMounted;
129 else
130 CLog::Log(LOGDEBUG, "UDisks: Is not able to unmount %s", toString().c_str());
132 return false;
135 CMediaSource CUDiskDevice::ToMediaShare()
137 CMediaSource source;
138 source.strPath = m_MountPath;
139 if (m_Label.empty())
141 std::string strSize = StringUtils::SizeToString(m_PartitionSize);
142 source.strName = StringUtils::Format("%s %s", strSize.c_str(), g_localizeStrings.Get(155).c_str());
144 else
145 source.strName = m_Label;
146 if (m_isOptical)
147 source.m_iDriveType = CMediaSource::SOURCE_TYPE_DVD;
148 else if (m_isSystemInternal)
149 source.m_iDriveType = CMediaSource::SOURCE_TYPE_LOCAL;
150 else
151 source.m_iDriveType = CMediaSource::SOURCE_TYPE_REMOVABLE;
152 source.m_ignore = true;
153 return source;
156 bool CUDiskDevice::IsApproved()
158 return (m_isFileSystem && m_isMounted && m_UDI.length() > 0 && (m_FileSystem.length() > 0 && m_FileSystem != "swap")
159 && m_MountPath != "/" && m_MountPath != "/boot") || m_isOptical;
162 #define BOOL2SZ(b) ((b) ? "true" : "false")
164 std::string CUDiskDevice::toString()
166 return StringUtils::Format("DeviceUDI %s: IsFileSystem %s HasFileSystem %s "
167 "IsSystemInternal %s IsMounted %s IsRemovable %s IsPartition %s "
168 "IsOptical %s",
169 m_DeviceKitUDI.c_str(), BOOL2SZ(m_isFileSystem), m_FileSystem.c_str(),
170 BOOL2SZ(m_isSystemInternal), BOOL2SZ(m_isMounted),
171 BOOL2SZ(m_isRemovable), BOOL2SZ(m_isPartition), BOOL2SZ(m_isOptical));
174 CUDisksProvider::CUDisksProvider()
176 dbus_error_init (&m_error);
177 //! @todo do not use dbus_connection_pop_message() that requires the use of a
178 //! private connection
179 m_connection = dbus_bus_get_private(DBUS_BUS_SYSTEM, &m_error);
181 if (m_connection)
183 dbus_connection_set_exit_on_disconnect(m_connection, false);
185 dbus_bus_add_match(m_connection, "type='signal',interface='org.freedesktop.UDisks'", &m_error);
186 dbus_connection_flush(m_connection);
189 if (dbus_error_is_set(&m_error))
191 CLog::Log(LOGERROR, "UDisks: Failed to attach to signal %s", m_error.message);
192 dbus_connection_close(m_connection);
193 dbus_connection_unref(m_connection);
194 m_connection = NULL;
198 CUDisksProvider::~CUDisksProvider()
200 DeviceMap::iterator itr;
202 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
203 delete m_AvailableDevices[itr->first];
205 m_AvailableDevices.clear();
207 if (m_connection)
209 dbus_connection_close(m_connection);
210 dbus_connection_unref(m_connection);
211 m_connection = NULL;
214 dbus_error_free (&m_error);
217 void CUDisksProvider::Initialize()
219 CLog::Log(LOGDEBUG, "Selected UDisks as storage provider");
220 m_DaemonVersion = atoi(CDBusUtil::GetVariant("org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "DaemonVersion").asString().c_str());
221 CLog::Log(LOGDEBUG, "UDisks: DaemonVersion %i", m_DaemonVersion);
223 CLog::Log(LOGDEBUG, "UDisks: Querying available devices");
224 std::vector<std::string> devices = EnumerateDisks();
225 for (unsigned int i = 0; i < devices.size(); i++)
226 DeviceAdded(devices[i].c_str(), NULL);
229 bool CUDisksProvider::Eject(const std::string& mountpath)
231 DeviceMap::iterator itr;
232 std::string path(mountpath);
233 URIUtils::RemoveSlashAtEnd(path);
235 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
237 CUDiskDevice *device = itr->second;
238 if (device->m_MountPath == path)
239 return device->UnMount();
242 return false;
245 std::vector<std::string> CUDisksProvider::GetDiskUsage()
247 CPosixMountProvider legacy;
248 return legacy.GetDiskUsage();
251 bool CUDisksProvider::PumpDriveChangeEvents(IStorageEventsCallback *callback)
253 bool result = false;
254 if (m_connection)
256 dbus_connection_read_write(m_connection, 0);
257 DBusMessage *msg = dbus_connection_pop_message(m_connection);
259 if (msg)
261 char *object;
262 if (dbus_message_get_args (msg, NULL, DBUS_TYPE_OBJECT_PATH, &object, DBUS_TYPE_INVALID))
264 result = true;
265 if (dbus_message_is_signal(msg, "org.freedesktop.UDisks", "DeviceAdded"))
266 DeviceAdded(object, callback);
267 else if (dbus_message_is_signal(msg, "org.freedesktop.UDisks", "DeviceRemoved"))
268 DeviceRemoved(object, callback);
269 else if (dbus_message_is_signal(msg, "org.freedesktop.UDisks", "DeviceChanged"))
270 DeviceChanged(object, callback);
272 dbus_message_unref(msg);
275 return result;
278 bool CUDisksProvider::HasUDisks()
280 bool hasUDisks = false;
281 CDBusMessage message("org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "EnumerateDevices");
283 DBusError error;
284 dbus_error_init (&error);
285 DBusConnection *con = dbus_bus_get(DBUS_BUS_SYSTEM, &error);
287 if (con)
288 message.Send(con, &error);
290 if (!dbus_error_is_set(&error))
291 hasUDisks = true;
292 else
293 CLog::Log(LOGDEBUG, "UDisks: %s - %s", error.name, error.message);
295 dbus_error_free (&error);
296 if (con)
297 dbus_connection_unref(con);
299 return hasUDisks;
302 void CUDisksProvider::DeviceAdded(const char *object, IStorageEventsCallback *callback)
304 if (g_advancedSettings.CanLogComponent(LOGDBUS))
305 CLog::Log(LOGDEBUG, "UDisks: DeviceAdded (%s)", object);
307 if (m_AvailableDevices[object])
309 CLog::Log(LOGWARNING, "UDisks: Inconsistency found! DeviceAdded on an indexed disk");
310 delete m_AvailableDevices[object];
313 CUDiskDevice *device = NULL;
314 device = new CUDiskDevice(object);
315 m_AvailableDevices[object] = device;
317 if (g_advancedSettings.m_handleMounting)
318 device->Mount();
320 if (g_advancedSettings.CanLogComponent(LOGDBUS))
321 CLog::Log(LOGDEBUG, "UDisks: DeviceAdded - %s", device->toString().c_str());
323 if (device->m_isMounted && device->IsApproved())
325 CLog::Log(LOGINFO, "UDisks: Added %s", device->m_MountPath.c_str());
326 if (callback)
327 callback->OnStorageAdded(device->m_Label, device->m_MountPath);
331 void CUDisksProvider::DeviceRemoved(const char *object, IStorageEventsCallback *callback)
333 if (g_advancedSettings.CanLogComponent(LOGDBUS))
334 CLog::Log(LOGDEBUG, "UDisks: DeviceRemoved (%s)", object);
336 CUDiskDevice *device = m_AvailableDevices[object];
337 if (device)
339 if (device->m_isMounted && callback)
340 callback->OnStorageUnsafelyRemoved(device->m_Label);
342 delete m_AvailableDevices[object];
343 m_AvailableDevices.erase(object);
347 void CUDisksProvider::DeviceChanged(const char *object, IStorageEventsCallback *callback)
349 if (g_advancedSettings.CanLogComponent(LOGDBUS))
350 CLog::Log(LOGDEBUG, "UDisks: DeviceChanged (%s)", object);
352 CUDiskDevice *device = m_AvailableDevices[object];
353 if (device == NULL)
355 CLog::Log(LOGWARNING, "UDisks: Inconsistency found! DeviceChanged on an unindexed disk");
356 DeviceAdded(object, callback);
358 else
360 bool mounted = device->m_isMounted;
361 /* make sure to not silently remount ejected usb thumb drives
362 that user wants to eject, but make sure to mount blurays */
363 if (!mounted && g_advancedSettings.m_handleMounting && device->m_isOptical)
364 device->Mount();
366 device->Update();
367 if (!mounted && device->m_isMounted && callback)
368 callback->OnStorageAdded(device->m_Label, device->m_MountPath);
369 else if (mounted && !device->m_isMounted && callback)
370 callback->OnStorageSafelyRemoved(device->m_Label);
372 if (g_advancedSettings.CanLogComponent(LOGDBUS))
373 CLog::Log(LOGDEBUG, "UDisks: DeviceChanged - %s", device->toString().c_str());
377 std::vector<std::string> CUDisksProvider::EnumerateDisks()
379 std::vector<std::string> devices;
380 CDBusMessage message("org.freedesktop.UDisks", "/org/freedesktop/UDisks", "org.freedesktop.UDisks", "EnumerateDevices");
381 DBusMessage *reply = message.SendSystem();
382 if (reply)
384 char** disks = NULL;
385 int length = 0;
387 if (dbus_message_get_args (reply, NULL, DBUS_TYPE_ARRAY, DBUS_TYPE_OBJECT_PATH, &disks, &length, DBUS_TYPE_INVALID))
389 for (int i = 0; i < length; i++)
390 devices.push_back(disks[i]);
392 dbus_free_string_array(disks);
396 return devices;
399 void CUDisksProvider::GetDisks(VECSOURCES& devices, bool EnumerateRemovable)
401 DeviceMap::iterator itr;
403 for (itr = m_AvailableDevices.begin(); itr != m_AvailableDevices.end(); ++itr)
405 CUDiskDevice *device = itr->second;
406 if (device && device->IsApproved() && device->m_isSystemInternal != EnumerateRemovable)
407 devices.push_back(device->ToMediaShare());
410 #endif